How to get strictly valid JSON from Rails

In: Ruby|Ruby on Rails|Web development

20 Jun 2007

Update: Edge Rails (and the forthcoming Rails 2.0) will emit only valid JSON. Read JSON serialization of ActiveRecord objects reaches maturity for more details.

If you’ve worked with JSON long enough in Rails, you’d probably have noticed that the JSON the convenient Object#to_json method spits out is not strictly JSON-compliant (according to the RFC 4627, which states that object keys should be “strings”, and “strings” should be double-quoted). Here’s an example of what to_json produces when called on an ActiveRecord instance:

{
  id: 6589,
  code: "SIN",
  name: "Singapore",
  type: "City"
}

Notice how the keys (id, code, name, type) are not surrounded with double quotes. While this is generally not a problem if working purely in Rails, since Prototype and Rails itself can decode JSON like this, you’d run into problems with more finicky JSON parsers and decoders. PHP’s json_decode is a perfect example – it demands that the object keys be double-quoted (or it fails to decode your JSON, silently returning NULL).

For a while I couldn’t figure out why Rails was doing it and Google was of no help. I decided to look at the Rails code since this can’t be a huge oversight on the Rails community, can it? Sure enough, I found the “solution” in the encoding portion of the ActiveSupport::JSON module:


  # When +true+, Hash#to_json will omit quoting string or symbol keys
  # if the keys are valid JavaScript identifiers.  Note that this is
  # technically improper JSON (all object keys must be quoted), so if
  # you need strict JSON compliance, set this option to +false+.
  mattr_accessor :unquote_hash_key_identifiers
  @@unquote_hash_key_identifiers = true

Doh! All that’s left to do is to put ActiveSupport::JSON.unquote_hash_key_identifiers = false in your environment.rb (or in the Rails initializers directory if you’re on edge) and your Rails app will start producing strictly valid JSON (and is friendlier to other non-Rails applications):

{
  "id": 6589,
  "code": "SIN",
  "name": "Singapore",
  "type": "City"
}

unquote_hash_key_identifiers was added in changeset 5486.

7 Responses to How to get strictly valid JSON from Rails

Avatar

Nathan Fiedler

June 21st, 2007 at 1am

Nice tip, thanks. Glad it’s easy to work around, but curious why they chose not to quote the keys…

Avatar

divotdave

June 23rd, 2007 at 3am

Nice work – I had earlier discovered this myself.

My main problem now is that when I use to_json on a collection object (i.e. @foo.to_json) the output includes a ‘attributes’ key for each record of data which makes it difficult for me to work with in Javascript when using a callback.

Like this:

list([{“attributes”: {“title”: “Here is my new story”}}, {“attributes”: {“title”: “I love this stuff!”}}, {“attributes”: {“title”: “Here is another story”}}])

I can’t figure out how to

A) remove the attributes key from the collection hash -or-
B) how to access the data I want around the repeated attributes values (i.e. title).

Any clue?

Thanks,
divotdave

Avatar

divotdave

June 23rd, 2007 at 5am

For the benefit of anyone else…

Each ‘attributes’ key constitutes a separate hash object with its own index (i.e. 0, 1, etc.). So to access the value of ‘title’ as in my previous post you would do this (in js of course):

var myObj = myJsonCallback(json_response);
alert(myObj[0].attributes.title);

Which will return the value “My first story” or whatever.

Cheers,
divotdave

Avatar

Gary

July 3rd, 2007 at 9pm

Near as I can tell, in JS the only place this type of JSON would work in the default configuration is in a pure Eval – which is usually a no-no. All the code I saw for more security conscious JSON parsing (e.g. Crockford) barfed on the unquoted keys, have to agree this is kinda weird behaviour by default.

Avatar

Better JSON output from Rails with the Jsonifier plugin - redemption in a blog

July 11th, 2007 at 12pm

[…] your environment.rb (or in the Rails initializers directory if you’re on edge). See my blog post on how to get strictly valid JSON from Rails for more info. Posted by Chu Yeow at July 11, 2007 SGT | Permalink | | Category: Ruby on Rails, […]

Avatar

Valid JSON from Rails Life is grand

September 28th, 2007 at 11pm

[…] it is pretty easy to tell Rails to emit valid JSON. Just set ActiveSupport::JSON.unquote_hash_key_identifiers = false in your […]

Avatar

Cameron Barrie

October 12th, 2007 at 10am

If you need to pass json without the attributes.

@object.attributes.to_json