You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I believe it's a fairly common idiom in Rails to return JSON by writing render json: some_object in a controller. That causes Rails to call some_object.to_json, and thus produce a json string to return.
Calling #to_json like this invokes Oj::Rails::Encoder when Oj.optimize_rails has been set up, which is what we want. However, the problem is that Rails actually calls to_json with a non-nil, non-empty options hash (it seems to have several actionview related keys like :prefixes, :template, and :layout, from my observation). Oj realises that it was called with options it doesn't understand, and thus saves those options here and forces a real call to the object's #as_json method with them here (because argc > 0. That meas real ActiveSupport Hash#as_json gets called, which actually makes a recursive duplicate of the hash - very expensive and not nescessary!
In our codebase, I'm doing something like the following to strip out these options in the call to to_json, and ensure that Oj can use the optimized, inlined implementations of those methods:
moduleJSONActionControllerRendererACTIONVIEW_RENDERER_KEYS=Set.new(%i[prefixestemplatelayout]).freezeRENDER_FUNC=->(json,options)do# Make sure we continue handling JSONP callbacks - the renderer needs this option, but Oj doesn't.callback=options.delete(:callback)# This bit makes the options go away, and Oj fast, if there are no options we don't understand.options=nilifoptions.all?{ |key,_value| ACTIONVIEW_RENDERER_KEYS.include?(key)}json=json.to_json(options)unlessjson.is_a?(String)ifcallback.present?ifmedia_type.nil? || media_type == Mime[:json]self.content_type=Mime[:js]end"/**/#{callback}(#{json})"elseself.content_type=Mime[:json]ifmedia_type.nil?jsonendend# Called from config/initializers/json.rb to register the rendererdefself.register!ActionController.remove_renderer:jsonActionController.add_renderer:json, &RENDER_FUNCendend
It would be good if this problem was solved "out of the box" somehow in Oj though. Options include:
Ship a custom ActionController renderer for :json just like the above snippet in Oj and enable it with Oj.optimize_rails
Make Oj::Rails::Encoder detect the options :template, :prefixes, and :layout explicitly, and strip them out
Suggest to the Rails people that these ActionView related options shouldn't be passed in to non-template renderers like :json, :xml & friends?
Do we think this is something we can solve in Oj?
The text was updated successfully, but these errors were encountered:
I believe it's a fairly common idiom in Rails to return JSON by writing
render json: some_object
in a controller. That causes Rails to callsome_object.to_json
, and thus produce a json string to return.Calling
#to_json
like this invokesOj::Rails::Encoder
whenOj.optimize_rails
has been set up, which is what we want. However, the problem is that Rails actually callsto_json
with a non-nil, non-empty options hash (it seems to have several actionview related keys like:prefixes
,:template
, and:layout
, from my observation). Oj realises that it was called with options it doesn't understand, and thus saves those options here and forces a real call to the object's#as_json
method with them here (becauseargc > 0
. That meas real ActiveSupportHash#as_json
gets called, which actually makes a recursive duplicate of the hash - very expensive and not nescessary!In our codebase, I'm doing something like the following to strip out these options in the call to
to_json
, and ensure that Oj can use the optimized, inlined implementations of those methods:It would be good if this problem was solved "out of the box" somehow in Oj though. Options include:
:json
just like the above snippet in Oj and enable it withOj.optimize_rails
Oj::Rails::Encoder
detect the options:template
,:prefixes
, and:layout
explicitly, and strip them out:json
,:xml
& friends?Do we think this is something we can solve in Oj?
The text was updated successfully, but these errors were encountered: