Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails as_json issue - How to include nested objects efficiently?

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.

like image 522
bluedevil2k Avatar asked Apr 26 '12 19:04

bluedevil2k


1 Answers

The best answer for me was using serializable_hash. @kikito touched on this in his comment, but there was a typo that prevented it from working. It's not serialized_hash, it's serializable_hash.

Literally just find + replace as_json with serializable_hash and this bug goes away. (It's still not fixed in today's Rails 4.0.2). You also get the benefit of having an easier time implementing an XML API later (some people still use those!).

like image 163
Mavvie Avatar answered Sep 20 '22 09:09

Mavvie