Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

as_json not calling as_json on associations

I have a model with data that should never be included when it is rendered as json. So I implemented the class' as_json method to behave appropriately. The problem is when other models with associations with this model render json, my custom as_json is not being called.

class Owner < ActiveRecord::Base   has_one :dog    def as_json(options={})     puts "Owner::as_json"     super(options)   end   end  class Dog < ActiveRecord::Base   belongs_to :owner    def as_json(options={})     puts "Dog::as_json"     options[:except] = :secret     super(options)   end   end 

Loading development environment (Rails 3.0.3)
ruby-1.9.2-p136 :001 > d = Dog.first
=> #<Dog id: 1, owner_id: 1, name: "Scooby", secret: "I enjoy crapping everwhere">
ruby-1.9.2-p136 :002 > d.as_json
Dog::as_json
=> {"dog"=>{"id"=>1, "name"=>"Scooby", "owner_id"=>1}}
ruby-1.9.2-p136 :004 > d.owner.as_json(:include => :dog)
Owner::as_json
=> {"owner"=>{"id"=>1, "name"=>"Shaggy", :dog=>{"id"=>1, "name"=>"Scooby", "owner_id"=>1, "secret"=>"I enjoy crapping everwhere"}}}

Thanks for the help

like image 255
nannerpus Avatar asked Jan 30 '11 03:01

nannerpus


Video Answer


2 Answers

This is a known bug in Rails. (The issue is marked closed due to the migration to Github issues from the previous bug tracker, but it's still a problem as of Rails 3.1.)

like image 98
John Avatar answered Oct 06 '22 05:10

John


As acknowledged above, this is an issue with the Rails base. The rails patch here is not yet applied and seems at least slightly controversial, so I'm hesitant to apply it locally. Even if applied as a monkey patch it could potentially complicate future rails upgrades.

I'm still considering RABL suggested above, it looks useful. For the moment, I'd rather not add another view templating language into my app. My current needs are very small.

So here's a workaround which doesn't require a patch and work for most simple cases. This works where the association's as_json method you'd like to have called looks like

def as_json(options={})   super( <... custom options ...> ) end 

In my case I've got Schedule model which has many Events

class Event < ActiveRecord::Base    # define json options as constant, or you could return them from a method   EVENT_JSON_OPTS = { :include => { :locations => { :only => [:id], :methods => [:name] } } }    def as_json(options={})     super(EVENT_JSON_OPTS)   end end  class Schedule < ActiveRecord::Base   has_many :events    def as_json(options={})     super(:include => { :events => { Event::EVENT_JSON_OPTS } })   end end 

If you followed the guideline that anytime you :include an association in your as_json() methods, you define any options you need as a constant in the model to be referenced, this would work for arbitrary levels of associations. NOTE I only needed the first level of association customized in the above example.

like image 22
shakerlxxv Avatar answered Oct 06 '22 03:10

shakerlxxv