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

Already on GitHub? Sign in to your account

JSON Serializer on datasets gives unexpected results. #549

Closed
bryanrite opened this Issue Sep 14, 2012 · 7 comments

Comments

Projects
None yet
3 participants

I have been using the json_serializer plugin for generating JSON for an API. Everything works great on single instances:

1.9.3p194 :001 > Relationship.first
 => #<Relationship @values={:id=>5, :on_air=>true, :created_at=>2012-09-13 12:47:12 -0700, :updated_at=>nil}> 
1.9.3p194 :002 > Relationship.first.to_json(naked: true, only: :id)
 => "{\"id\":5}"

When I want to convert a collection of Relationship objects, I get some unexpected results:

1.9.3p194 :004 > Relationship.all.to_json(naked: true, only: :id)
 => "[{\"id\":5,\"on_air\":true,\"created_at\":\"2012-09-13T12:47:12-07:00\",\"updated_at\":null},{\"id\":6,\"on_air\":true,\"created_at\":\"2012-09-13T12:47:55-07:00\",\"updated_at\":null},{\"id\":7,\"on_air\":true,\"created_at\":\"2012-09-13T12:48:29-07:00\",\"updated_at\":null}]" 

It generates proper JSON, but does not take options into account. I understand this is running to_json on an instance of Array.

Using filters as the documentation shows:

1.9.3p194 :005 > Relationship.filter().to_json(naked: true, only: :id)
 => "[{\"json\":\"{\\\"id\\\":5}\"},{\"json\":\"{\\\"id\\\":6}\"},{\"json\":\"{\\\"id\\\":7}\"}]" 

Produces a better dataset but not valid JSON. Looks like its been encoded twice.

Using the array: option produces the same as above:

1.9.3p194 :021 > Relationship.to_json(array: Relationship.filter(), naked: true, only: :id)
 => "[{\"json\":\"{\\\"id\\\":5}\"},{\"json\":\"{\\\"id\\\":6}\"},{\"json\":\"{\\\"id\\\":7}\"}]"

What I would expect is something more like:

"[{\"id\":5},{\"id\":6},{\"id\":7}]"

Is this the intended behaviour?

Owner

jeremyevans commented Sep 14, 2012

ruby's json library defines Array#to_json such that it does not pass arguments given to it to members of the array, which is why Model.all.to_json will not respect an options hash if you pass one. That is expected.

The other results with the double encoding are because you are using 'active_support/json', which breaks Sequel's json_serializer plugin because it changes the to_json API. Basically active_support/json makes incompatible changes to ruby's json library. I consider this a bug in ActiveSupport.

This question has come up before, I'll add a note to the plugin documentation to be explicit that the problem is with ActiveSupport.

Thanks Jeremy. I was using Carrierwave which requires activesupport and I didn't realize this was happening. Thanks for your tips on undoing this as well.

Contributor

Aryk commented Mar 1, 2017 edited

Just FYI as I know this is old...

In ActiveSupport v5, there is a way to bypass ActiveSupport#to_json and use the normal to_json via ::JSON.{generate,dump}(obj). From the documentation for AS > version 5:

It should be noted that when using ::JSON.{generate,dump} directly, ActiveSupport's encoder is bypassed completely.

Owner

jeremyevans commented Mar 1, 2017

That's a good point, but unfortunately I think changing Sequel's default behavior it would break compatibility who have overwritten to_json manually. However, we can probably make that change in Sequel 5.

Contributor

Aryk commented Mar 2, 2017

Yeah, the whole to_json thing is quite a nasty issue due to ActiveSupport's treatment of things. They are some redeeming qualities however. I like the as_json convention as a precursor to the to_json.

Many times, like in testcases, etc, I want to see the hash version of the json. In your serializer, you essentially create a hash and to_json it (with some idiosyncrasies), but I can't access the actual hash in case I want to make further edits.

Perhaps there is an opportunity to create some kind of ActiveSupport Json Serializer plugin for Sequel that hooks into the as_json method so that I can construct a hash representation but use options like :include and :root.

Thoughts?

Owner

jeremyevans commented Mar 2, 2017

I'm leery of using any additional parts of ActiveSupport in the plugins/extensions that ship with Sequel (we currently use ActiveModel::Naming in the active_model plugin and ActiveSupport::Duration in the pg_interval plugin). But that sounds like a good idea for an external plugin.

Contributor

Aryk commented Mar 2, 2017

Makes sense! Will look into making an extension if it becomes a burning problem. For now I'm just using the JSON.dump which seems to be ok...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment