Rails as_json weirdness

While fixing a broken test, I came across this weirdness with as_json:

Huh?

Here’s an example with a class called Post with attributes for id, title, and body. It also has an instance method:

class Post < ActiveRecord::Base

  def hello_world
    "hello world"
  end
end

The output from as_json is a Hash and all the keys are strings:

>> post.as_json
=> {"body"=>"test body", "id"=>30, "title"=>"Hi"}

>> post.as_json.class
=> Hash

When referring to a method in Ruby, you usually use a symbol, but this will use that symbol as the key:

>> post.as_json(:methods => [:hello_world])
=> {"body"=>"test body", "id"=>30, "title"=>"Hi", :hello_world=>"hello world"}

However, you can also use a string as the method name, and it will use a string instead:

>> post.as_json(:methods => ['hello_world'])
=> {"body"=>"test body", "id"=>30, "title"=>"Hi", "hello_world"=>"hello world"}

Strange! It doesn’t usually matter because this output gets passed to to_json and the symbols are converted to strings, but it was inconvenient in my test case, because I was using strings as keys. Once I figured it out I was able to work around it.

This was tested in Rails 3.2.5.