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.