Closed TrevorHinesley closed 7 years ago
What call are you making to encode an object to JSON? There are 4 approaches.
Oj.dump(x, mode: :rails, indent: ' ')
x.to_json(indent: ' ')
JSON.generate(x, indent: ' ')
ActiveSupport::JSON.encode(x)
In all cases the mode is either Rails or in the car of 3, the json gem compatibility mode. In those mode the indent option must be a string and other formatting options should be used. That is the way the json gem and Rails work so in mimicking Oj does the same.
Also not that the call to encode does not support options.
I'm using ActiveModel Serializers in JSONAPI mode. So it just renders like so:
render jsonapi: @obj
I am not familiar with the jsonapi-render but looking at the project it appears to use the as_jsonapi() method instead of the Rails as_json() method. Maybe that project should be looped into this issue if you want to proceed. It may be that Oj is not being called at all.
Actually, it's using to_json
from what I can tell (maybe I'm missing something):
That gives me a starting point. I follow that back and find out what the to_json call does.
Can you put in a the following line just above line 45 of register_jsonapi_renderer.rb and run so we can see that class has to_json() being called?
puts "*** #{serialize_jsonapi(json, options).class}"
I tried to follow the active support code but it goes through so many twists and turned and depends on what variables are set that it's next to impossible to follow.
@ohler55 It showed up as ActiveModelSerializers::SerializableResource
Ok, now lets print out the results of the to_json and as_json. Some background first. Both the json gem and rails monkey patch to_json. Usually the json gem is loaded first and the to_json is monkey patched a second time by rails. By calling Oj.mimic_JSON the to_json method is gain monkey patched. That might be the problem but let check to make sure.
Right after the puts that we added print out the encoded value and since to_json calls as_json try that too.
puts "*** as_json: #{serialize_jsonapi(json, options).as_json()}"
puts "*** to_json: #{serialize_jsonapi(json, options).to_json(options)}"
Run the program without Oj then with Oj but without the Oj.mimic_JSON but keep the Oj.optimize_rails(), finally the way you described at the start of the issue.
EDIT: These were wrong. My initializer wasn't setup properly.
Without Oj:
*** ActiveModelSerializers::SerializableResource
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (4.68ms)
*** as_json: {:data=>{:id=>"1", :type=>"invoices", :attributes=>{:date=>Thu, 25 May 2017 15:16:33 UTC +00:00, :stripe_id=>"in_1ANNhVJ7bX4xZXpH3m8t6nO6", :status=>"paid"}}}
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (0.65ms)
*** to_json: {"data":{"id":"1","type":"invoices","attributes":{"date":"2017-05-25T15:16:33.000Z","stripe_id":"in_1ANNhVJ7bX4xZXpH3m8t6nO6","status":"paid"}}}
With Oj configured as:
Oj.default_options = { mode: :rails }
Oj.optimize_rails()
*** ActiveModelSerializers::SerializableResource
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (3.68ms)
*** as_json: {:data=>{:id=>"1", :type=>"invoices", :attributes=>{:date=>Thu, 25 May 2017 15:16:33 UTC +00:00, :stripe_id=>"in_1ANNhVJ7bX4xZXpH3m8t6nO6", :status=>"paid"}}}
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (0.99ms)
*** to_json: {"data":{"id":"1","type":"invoices","attributes":{"date":"2017-05-25T15:16:33.000Z","stripe_id":"in_1ANNhVJ7bX4xZXpH3m8t6nO6","status":"paid"}}}
And lastly, the way I described:
Oj.mimic_JSON()
Oj.default_options = { mode: :rails, indent: 10 }
Oj.optimize_rails()
*** ActiveModelSerializers::SerializableResource
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (4.7ms)
*** as_json: {:data=>{:id=>"1", :type=>"invoices", :attributes=>{:date=>Thu, 25 May 2017 15:16:33 UTC +00:00, :stripe_id=>"in_1ANNhVJ7bX4xZXpH3m8t6nO6", :status=>"paid"}}}
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (0.61ms)
*** to_json: {"data":{"id":"1","type":"invoices","attributes":{"date":"2017-05-25T15:16:33.000Z","stripe_id":"in_1ANNhVJ7bX4xZXpH3m8t6nO6","status":"paid"}}}
Well this is strange, if I put those 3 Oj configuration lines in the controller instead of an initializer, and require 'oj' just to be sure, I get:
undefined method `optimize_rails' for Oj:Module
Removing that line, the indent shows up properly--turns out my initializer wasn't set up right (it was in config/ instead of config/initializers/ on accident):
*** ActiveModelSerializers::SerializableResource
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (0.65ms)
*** as_json: {:data=>{:id=>"1", :type=>"invoices", :attributes=>{:date=>Thu, 25 May 2017 15:16:33 UTC +00:00, :stripe_id=>"in_1ANNhVJ7bX4xZXpH3m8t6nO6", :status=>"paid"}}}
[active_model_serializers] Rendered V1::InvoiceSerializer with ActiveModelSerializers::Adapter::JsonApi (0.43ms)
*** to_json: {
"data":{
"id":"1",
"type":"invoices",
"attributes":{
"date":"2017-05-25T15:16:33.000Z",
"stripe_id":"in_1ANNhVJ7bX4xZXpH3m8t6nO6",
"status":"paid"
}
}
}
Why is optimize_rails() throwing an error though?
I also get these warnings:
/Users/Trevor/.rvm/gems/ruby-2.3.1/gems/oj-3.0.3/lib/oj/json.rb:95: warning: already initialized constant JSON::State
/Users/Trevor/.rvm/gems/ruby-2.3.1/gems/json-2.1.0/lib/json/common.rb:67: warning: previous definition of State was here
/Users/Trevor/.rvm/gems/ruby-2.3.1/gems/oj-3.0.3/lib/oj/json.rb:101: warning: already initialized constant JSON::Parser
/Users/Trevor/.rvm/gems/ruby-2.3.1/gems/json-2.1.0/lib/json/common.rb:29: warning: previous definition of Parser was here
Starting from the warnings. Oj is replacing the json gem so the warnings are expected. Switch to Oj 3.0.10 and I think they will be gone.
Odd that the 3 variations all return the same result from to_json yet you get an error with just the Oj one. Something doesn't add up.
optimize_rails was not in 3.0.3. It was added in 3.0.6.
Ya the 3 variations were because my initializer wasn't actually setting everything. Edited that comment to reflect that. With 3.0.10 all is good. Thanks so much, and sorry for the confusion!
That is good news. Thanks for closing.
I have an initializer:
But I've tried setting indent to like 10 to see if the raw response was any different, and I'm not seeing anything different. Do I have this configured wrong? Do I need the
optimize_rails
call at all?