render :json => ‘string here’ expected result

I agree that this is unexpected behavior at first, but it actually makes some good sense.

Consider, for example, what you would expect this to do:

output = {'foo' => 'bar'}.to_json
render :json => output

Even though the to_json is kinda redundant, you expect the result to be {foo: "bar"}. However, note that the result of {'foo' => 'bar'}.to_json is actually a string. So, the above code block is equivalent to:

render :json => '{foo: "bar"}'

If render were to JSON-encode strings passed to :json, you would get "{foo: \"bar\"}", which is definitely not expected behavior.

So here’s the deal: render checks to see if the :json argument is a string. If so, it assumes that it’s a JSON string and you already ran to_json, and passes the string along. If not, it runs to_json on the object.

I think the documentation should probably clarify that, but there you have it. Though it’s not exactly intuitive at first glance, I would be surprised if it worked any other way.

Leave a Comment