Rails as_json issue - How to include nested objects efficiently?

ruby, ruby-on-rails, ruby-on-rails-3

Solution

Which version of Rails are you using? This is a known bug in older versions of Rails, supposedly fixed with this pull request. Your syntax looks right to me, so perhaps this is your problem?

As an aside, you may also want to checkout the new active_model_serializers from Jose Valim (Rails core member). It may at least enable you to work around your issue in a more elegant manner.

Problem

I'm running into an issue where I'm working with the as_json method, and how to efficiently return the object in JSON AND it's belongs_to object as JSON as well, where the belongs_to object has its own belongs_to object. Code would probably explain it better. The Not-Working Way Alert class ``` class Alert < ActiveRecord::Base belongs_to :message # for json rendering def as_json(options={}) super(:include => :message) end end ``` Message class ``` def as_json(options={}) super( methods: [:timestamp, :num_photos, :first_photo_url, :tag_names], include: { camera: { only: [:id, :name] }, position: { only: [:id, :name, :address, :default_threat_level ]}, images: { only: [:id, :photo_url, :is_hidden]} }) end ``` The problem with this first set up is that when I have an Alert object and call ``` alert.as_json() ``` I get all the attributes from Alert and all the attributes from Message, but none of the other attributes from Message that I want, like Camera, Position, etc. Here's the "It's Working, But Probably Not Proper Design Way" Alert Class ``` class Alert < ActiveRecord::Base belongs_to :message # for json rendering def as_json(options={}) super().merge(:message => message.as_json) end end ``` Messages Class ``` # for json rendering def as_json(options={}) super( methods: [:timestamp, :num_photos, :first_photo_url, :tag_names]) .merge(:camera => camera.as_json) .merge(:position => position.as_json) .merge(:images => images.as_json) end ``` In this 2nd setup, I get all of Messages's nested attributes like I want. My question, am I missing some Rails Convention to do this properly? It seems like there would/should be an easier way.

Original source