开发者

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
  belo开发者_运维知识库ngs_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


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.)


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.


I've found that serializable_hash works just as you'd expect as_json to work, and is always called:

  def serializable_hash(options = {})
    result = super(options)
    result[:url] = "http://.."
    result
  end


I ran into the same issue. I wanted this to work:

render :json => @favorites.as_json(:include => :location)

But it didn't so I ended up adding an index.json.erb with the following:

<% favs = @favorites.as_json.each do |fav| %>
    <% fav["location"] = Location.find(fav["location_id"]).as_json %>
<% end %>
<%= favs.to_json.html_safe %>

Not a fix - just a work around. I imagine you did the same thing.


Update @John pointed out this is a known bug in Rails. A patch to fix it appears to be: at https://github.com/rails/rails/pull/2200. Nevertheless, you might try RABL, because its sweet.

I've always been frustrated with passing a complex set of options to create the JSON views I want. Your problem, which I experienced with Mongoid in Rails 3.0.9, prompted me to write JSON templates. But actually, if you're dealing with relations or custom api properties, it turns out that templates are way nicer.

Besides, dealing with different outputs seems like the View layer to me, so I settled on using RABL, the API templating language. It makes it super easy to build valid JSON and include any associations or fields.

Not a solution to the problem, but a better solution for the use case.


This was reported as a bug: http://ternarylabs.com/2010/09/07/migrating-to-rails-3-0-gotchas-as_json-bug/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜