This project is archived and is in readonly mode.
ActiveSupport::JSON.encode fails for Struct types
Reported by Mark A. Richman | November 28th, 2010 @ 05:46 AM | in 3.x
I am using DataMapper's repository.adapter.select
to retrieve results of an arbitrary query. The results are returned
as an array of structs, each of which looks like the following:
#<struct matches_id=52276, begin_date=Sun, 28 Nov 2010 20:30:00 -0500, windows_time_zone="E. South America Standard Time", team1_id=1430, team2_id=373, team1="Avaí Futebol Clube", team2="Santos Futebol Clube", status="N", match_day_name="Rodada 37", season_name="Brasileirão Série A", round_name="Brasileirão Série A", competition_name="Brasileirão Série A", group_name="", use_gsm="Y", team1_score=0, team2_score=0>
Calling #to_json on this struct throws the following exception:
NoMethodError: undefined method `encode_json' for Sun, 28 Nov 2010 20:30:00 -0500:DateTime
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/json/encoding.rb:214:in `block in encode_json'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/json/encoding.rb:214:in `map'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/json/encoding.rb:214:in `encode_json'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/json/encoding.rb:47:in `block in encode'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/json/encoding.rb:77:in `check_for_circular_references'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/json/encoding.rb:45:in `encode'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/json/encoding.rb:30:in `encode'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/activesupport-3.0.3/lib/active_support/core_ext/object/to_json.rb:20:in `to_json'
from (irb):8
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/railties-3.0.3/lib/rails/commands/console.rb:44:in `start'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/railties-3.0.3/lib/rails/commands/console.rb:8:in `start'
from /Users/mark/.rvm/gems/ruby-1.9.2-head/gems/railties-3.0.3/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
The exception does not seem to be related to the DateTime type, since I can convert this struct to a hash and that will serialize to JSON without error:
Hash[row.members.zip(row.values)] =>
{:matches_id=>52276, :begin_date=>Sun, 28 Nov 2010 20:30:00 -0500, :windows_time_zone=>"E. South America Standard Time", :team1_id=>1430, :team2_id=>373, :team1=>"Avaí Futebol Clube", :team2=>"Santos Futebol Clube", :status=>"N", :match_day_name=>"Rodada 37", :season_name=>"Brasileirão Série A", :round_name=>"Brasileirão Série A", :competition_name=>"Brasileirão Série A", :group_name=>"", :use_gsm=>"Y", :team1_score=>0, :team2_score=>0}
which produces correct JSON on #to_json:
=> "{\"matches_id\":52276,\"begin_date\":\"2010-11-28T20:30:00-05:00\",\"windows_time_zone\":\"E. South America Standard Time\",\"team1_id\":1430,\"team2_id\":373,\"team1\":\"Ava\\u00ed Futebol Clube\",\"team2\":\"Santos Futebol Clube\",\"status\":\"N\",\"match_day_name\":\"Rodada 37\",\"season_name\":\"Brasileir\\u00e3o S\\u00e9rie A\",\"round_name\":\"Brasileir\\u00e3o S\\u00e9rie A\",\"competition_name\":\"Brasileir\\u00e3o S\\u00e9rie A\",\"group_name\":\"\",\"use_gsm\":\"Y\",\"team1_score\":0,\"team2_score\":0}"
Struct support should be added OR perhaps a pointer to some documentation on how I can expect AS::JSON in my own project to work with Struct. I think it's ok to do a local hack like the one I did temporarily, but I'd rather see this handled in Rails, or at the very least in some project specific override.
Thanks,
Mark
Comments and changes to this ticket
-
iain December 8th, 2010 @ 08:37 PM
- Tag changed from json to_json encode struct to as_json, encode_json, json, to_json
+1
It's not really a problem with Structs, but with classes included in native structures.
A test case:
class Sub def as_json(*) { :foo => "bar" } end end class Base def as_json(*) [ Sub.new ] end end puts Base.new.to_json
Resulting in the error reported:
[GEM_HOME]/activesupport-3.0.3/lib/active_support/json/encoding.rb:214:in `encode_json': undefined method `encode_json' for #<Sub:0x102a02a78> (NoMethodError) from [GEM_HOME]/activesupport-3.0.3/lib/active_support/json/encoding.rb:214:in `map' from [GEM_HOME]/activesupport-3.0.3/lib/active_support/json/encoding.rb:214:in `encode_json' from [GEM_HOME]/activesupport-3.0.3/lib/active_support/json/encoding.rb:47:in `encode' from [GEM_HOME]/activesupport-3.0.3/lib/active_support/json/encoding.rb:77:in `check_for_circular_references' from [GEM_HOME]/activesupport-3.0.3/lib/active_support/json/encoding.rb:45:in `encode' from [GEM_HOME]/activesupport-3.0.3/lib/active_support/json/encoding.rb:30:in `encode' from [GEM_HOME]/activesupport-3.0.3/lib/active_support/core_ext/object/to_json.rb:15:in `to_json' from json_test.rb:15
-
iain December 8th, 2010 @ 08:42 PM
BTW: this issue was introduced in Rails 3.0.2, the above code works fine in Rails 3.0.1
-
Mark A. Richman December 8th, 2010 @ 09:02 PM
Would you mind pasting your json_test.rb so I can see what you did?
-
iain December 8th, 2010 @ 09:33 PM
json_test.rb is the code I showed (minus a "require 'config/environment'" line to load my Rails app).
To fix it, we need to dig in activesupport/lib/active_support/json/encoding.rb and see what has been changed. -
John Firebaugh December 9th, 2010 @ 12:58 AM
A custom #as_json definition should usually call Array#as_json or Hash#as_json itself. For example, the correct definition in the example above is:
class Base def as_json(*args) [ Sub.new ].as_json(*args) end end
Object#as_json has a similar bug, which is causing Mark's exception. It should call #as_json on the result of #to_hash or #instance_values:
class Object def as_json(options = nil) #:nodoc: if respond_to?(:to_hash) to_hash else instance_values end.as_json(options) end end
-
bgallet December 11th, 2010 @ 09:54 PM
I cannot reproduce this, however, it is not behaving as expected.
Struct.new("StructTest", :name, :address) puts Struct::StructTest.new("Dave", "value").to_json # => ["Dave","121 Main st."]
I would have expected: { "name": "Dave", "address": "121 Main st." }
-
jasereja January 11th, 2011 @ 01:49 PM
I have same problem.
Use mongoid and try respond_to :jsonIn rails 3.0.1 it work nice. higher versions broken.
-
Alexey Nayden January 13th, 2011 @ 12:35 AM
- Assigned user set to Jeremy Kemper
- Tag changed from as_json, encode_json, json, to_json to as_json, encode_json, json, patch, to_json
-
Neeraj Singh January 13th, 2011 @ 02:46 AM
- Milestone set to 3.x
- State changed from new to open
- Importance changed from to Low
Here is a patch with test.
https://github.com/neerajdotname/rails/commit/e9931f1df28eb97c53a92...
-
Neeraj Singh January 13th, 2011 @ 02:01 PM
sorry I did not see there was already a patch for it. Ignore me.
-
Alexey Nayden January 13th, 2011 @ 08:47 PM
@Neeraj no problem. So are you going to apply my patch? Or maybe I shall reassign the ticket to someone else?
-
Neeraj Singh January 13th, 2011 @ 10:57 PM
I can't apply your patch. Only core team can do that. I can +1 this ticket.
+1
-
Alexey Nayden January 13th, 2011 @ 11:21 PM
- Assigned user changed from Jeremy Kemper to Santiago Pastorino
-
Alexey Nayden January 13th, 2011 @ 11:23 PM
Santiago, would you please apply my patch? It seems to be useful bugfix.
-
Repository January 15th, 2011 @ 02:07 AM
- State changed from open to committed
(from [a9163b547c7cfd4861c814371fa9d1a6bdb31231]) Complex struct encoding fix
[#6077 state:committed]
Signed-off-by: Santiago Pastorino santiago@wyeworks.com
https://github.com/rails/rails/commit/a9163b547c7cfd4861c814371fa9d... -
Bryce Kerley January 17th, 2011 @ 04:24 AM
I'm getting a test failure on this in 1.9.2-p136, due to hash ordering:
test_struct_encoding(TestJSONEncoding) [test/json/encoding_test.rb:239]: <"{\"sub\":{\"name\":\"David\",\"date\":\"2010/01/01\"},\"name\":\"David\"}"> expected but was <"{\"name\":\"David\",\"sub\":{\"name\":\"David\",\"date\":\"2010/01/01\"}}">.
Should the expected struct ordering be canonical? If not, I've patched the expected ordering in the test at https://github.com/bkerley/rails/commit/b9d05c3fff974e59b4e06da68d9... .
-
Mike (at coverallcrew) February 11th, 2011 @ 08:28 PM
This is still failing for me with Rails 3.0.4
To replicate, try using Mongoid or MongoMapper with anything higher than Rails 3.0.1
-
Santiago Pastorino February 11th, 2011 @ 10:24 PM
Have you tried this against master?
I guess we haven't backported to 3-0-stable?
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Attachments
Tags
Referenced by
- 6077 ActiveSupport::JSON.encode fails for Struct types [#6077 state:committed]