It seems that when returning an object containing a "type" attribute as JSON from a Rails 3.1 application, the "type" attribute is not included. Assume I have the following:
A model with corresponding STI table Animal. Models Cat, Dog and Fish that inherit Animal.
When returning an Animal via JSON, I wish to include the "type" column, but this is not happening:
jQuery.ajax("http://localhost:3001/animals/1", {dataType: "json"});
yields:
responseText: "{"can_swim":false,"created_at":"2012-01-20T17:55:16Z","id":1,"name":"Fluffy","updated_at":"2012-01-20T17:55:16Z","weight":9.0}"
It seems like this is a problem with to_json:
bash-3.2$ rails runner 'p Animal.first.to_yaml'
"--- !ruby/object:Cat\nattributes:\n id: 1\n type: Cat\n weight: 9.0\n name: Fluffy\n can_swim: false\n created_at: 2012-01-20 17:55:16.090646000 Z\n updated_at: 2012-01-20 17:55:16.090646000 Z\n"
bash-3.2$ rails runner 'p Animal.first.to_json'
"{\"can_swim\":false,\"created_at\":\"2012-01-20T17:55:16Z\",\"id\":1,\"name\":\"Fluffy\",\"updated_at\":\"2012-01-20T17:55:16Z\",\"weight\":9.0}"
Does anyone know the reasoning behind this behavior, and how to override it?
For me, in Rails 2.3.12, the above does not work.
I can (in my Model of course) do something like this:
class Registration < ActiveRecord::Base
def as_json(options={})
super(options.merge(:include => [:type]))
end
end
But that causes to_json to throw an error like this:
NoMethodError: undefined method `serializable_hash' for "Registration":String
I've worked around this with this, which is punches this method onto the object I want to export
class Registration < ActiveRecord::Base
def as_json(options={})
super(options.merge(:include => [:type]))
end
def type
r = self.attributes["type"]
def r.serializable_hash(arg)
self
end
r
end
end
So on my app, I've put this into a mixin:
module RailsStiModel
# The following two methods add the "type" parameter to the to_json output.
# see also:
# http://stackoverflow.com/questions/8945846/including-type-attribute-in-json-respond-with-rails-3-1/15293715#15293715
def as_json(options={})
super(options.merge(:include => [:type]))
end
def type
r = self.attributes["type"]
def r.serializable_hash(arg)
self
end
r
end
end
And now in my model class(es), I add:
include RailsStiModel
This is what i did. It just adds the missing type
to the result set
def as_json(options={})
super(options.merge({:methods => :type}))
end
Override the as_json method. It's used by to_json
in order to produce the output. You can do something like:
def as_json options={}
{
id: id,
can_swim: can_swim,
type: type
}
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With