Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.to_json ignores .as_json but render json: doesn't #540

Closed
omnibs opened this issue May 27, 2019 · 7 comments
Closed

.to_json ignores .as_json but render json: doesn't #540

omnibs opened this issue May 27, 2019 · 7 comments

Comments

@omnibs
Copy link

omnibs commented May 27, 2019

I'm struggling to understand this behavior, not sure if I'm approaching things with the wrong expectation here or if I'm misunderstanding the modes and settings, but I can't find a way to make .to_json and render json: to have consistent behavior when overriding as_json.

In my application.rb:

require 'oj'

Oj::Rails.set_encoder()
Oj::Rails.set_decoder()
Oj::Rails.optimize()
Oj::Rails.mimic_JSON()

A Module with overridden as_json:

module Something
  def self.as_json(_opts = nil)
    { tag: :Submitted }
  end
end
  • When I render json: Something I get {"tag":"Submitted"}
  • When I Something.to_json I get "Something"

An example app demonstrating the behavior: https://repl.it/repls/ComfortableWhoppingWorkspaces

@ohler55
Copy link
Owner

ohler55 commented May 27, 2019

I feel your pain. I have struggled for a long time to mimic the rails and JSON behavior when they are combined. It is very finicky.

I suspect you will see similar behavior with rails and the JSON gem. I believe render will use rails while .to_json uses the JSON gem. Oj does it's best to mimic that behavior. Having said that, it seems odd that the class name is returned. What does the to_json method look like?

Something you could try would be to put the Oj::Rails.mimic_JSON() before the OJ rails calls.

@omnibs
Copy link
Author

omnibs commented May 27, 2019

Thanks for the quick response! It helps to know I'm not misunderstanding the docs and this is actually hard! =]

I'll do some more testing soon and report back!

What does the to_json method look like?

I'm not sure what you mean by what does it look like. Like, what code paths it actually executes? I'm not sure how to check that besides pry and stepping into things, so if you have any tips on how to check this I'd be super thankful!

@ohler55
Copy link
Owner

ohler55 commented May 27, 2019

There are some trace options that can be used. Oj has a trace option as well.

I think you will find that the JSON gem sets up the to_json methods directly and does not call as_json. With rails in the mix then as_json is called when encoding as JSON. Generally avoid direct calls to to_json to avoid issues. If using rails call the rails encoder and decoders.

@ohler55
Copy link
Owner

ohler55 commented Jun 4, 2019

Any thing else I can help you with?

@omnibs
Copy link
Author

omnibs commented Jun 14, 2019

Sorry for the lack of comm, I haven't poked at this again and don't know when I'll have time. Closing the issue. Will reopen if I have any trouble.

Thanks for the help!

@omnibs omnibs closed this as completed Jun 14, 2019
@KJTsanaktsidis
Copy link
Contributor

I just ran into this, I'm fairly certain it's because render :json passes options to to_json - a hash with keys :prefixes, :template, and :layout. Oj sees these options in Oj::Rails::Encoder.new, saves them, and then when running Oj::Rails::Encoder#encode, sees that options were passed and thus realises that it must call #as_json because options were present:

oj/ext/oj/rails.c

Line 1343 in 0032fbb

if ((!oj_rails_hash_opt || 0 < out->argc) && as_ok && rb_respond_to(obj, oj_as_json_id)) {

I might try and solve this in our app by overwriting what render json: does to not pass any options. Perhaps this is also something that optimize_rails could do?

@KJTsanaktsidis
Copy link
Contributor

I opened a new issue to discuss this specific problem with render json I discovered: #913

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants