CrudVision - Lisa Seelye

July 6, 2007

Rails JSON is broken

Filed under: json, rails, ruby, snippet, work — Lisa Seelye @ 23:12

At work yesterday I found out that by default ActiveSupport::JSON.unquote_hash_key_identifiers is true. This means that a JSON string looks like:

{attributes: {name: "0-3VW8 I", coordinate_id: "6229", system_id: "30000995", id: "40063299", igbtype: "7"}}

Flash JSON decoders (and probably others) expect the above attributes word to be doublequoted. This is achieved (after much Googling) by setting ActiveSupport::JSON.unquote_hash_key_identifiers=false.

But it doesn't stop there. In the above JSON output the IDs are quoted, that means they're encoded as strings and not integers. This is against the spec.

This means that

RUBY:
  1. ActiveSupport::JSON.unquote_hash_key_identifiers = false
  2. planet = Planet.find :first
  3. print planet.to_json # => {"attributes": {name: "0-3VW8 I", coordinate_id: "6229", system_id: "30000995", id: "40063299", igbtype: "7"}}

The integers should not be double quoted.

With the help of lifo from #rails-contrib the problem seems to have been narrowed down to instance_values/instance_variable_get borking things up. From my poking around (n.b., I'm not all that experienced with the source for Rails itself! I may be wrong) the issue seems to lay within vendor/rails/activesupport/lib/active_support/json/encoders/object.rb. This bit of code seems to work for AR::Base derived models:

RUBY:
  1. class ActiveRecord::Base
  2. def to_json
  3. ret = ActiveSupport::JSON.unquote_hash_key_identifiers ? "{attributes: " : '{"attributes": '
  4. ret + self.attributes.to_json + '}'
  5. end
  6. end

Edit (10 July 2007): It seems that this isn't exactly a drop-in replacement fix: If a model has associations loaded (Foo.find :first, :include => :bars) the above JSON-fixing snippet will not work because it looks at attributes only and not the loaded associations. I'll have to work around that.

Powered by WordPress