27

I'd love to use render :json but it seems its not as flexible. Whats the right way to do this?

respond_to do |format|
  format.html # index.html.erb
  format.xml  { render :xml => @things }

  #This is great
  format.json { render :text => @things.to_json(:include => :photos) }

  #This doesn't include photos
  format.json { render :json => @things, :include => :photos }
end
GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337

5 Answers5

39

I've done something similar with render :json. This is what worked for me:

respond_to do |format|
    format.html # index.html.erb
    format.json  { render :json => @things.to_json(:include => { :photos => { :only => [:id, :url] } }) }
end
Justin Gallagher
  • 3,242
  • 21
  • 25
35

I guess this article can be useful for you - Rails to_json or as_json? by Jonathan Julian.

The main thought is that you should avoid using to_json in controllers. It is much more flexible to define as_json method in your model.

For instance:

In your Thing model

def as_json(options={})
  super(:include => :photos)
end

And then you can write in your controller just

render :json => @things
Benjamin Oakes
  • 12,262
  • 12
  • 65
  • 83
cutalion
  • 4,334
  • 1
  • 38
  • 47
  • 2
    Might want to do `super(options.merge(:include => :photos))` to preserve other possible passed-in options. You would still override any `:include` options, though... the logic for merging values for that key would get a bit more involved. – Abe Voelker Sep 12 '12 at 19:08
  • Using `super options.reverse_merge :include => :photos` would allow you to override the "default" :include. (See [Hash#reverse_merge](http://api.rubyonrails.org/classes/Hash.html#method-i-reverse_merge)) – Steve Oct 26 '15 at 20:44
3

Managing complex hashes in your controllers gets ugly fast.

With Rails 3, you can use ActiveModel::Serializer. See http://api.rubyonrails.org/classes/ActiveModel/Serialization.html

If you're doing anything non-trivial, see https://github.com/rails-api/active_model_serializers. I recommend creating separate serializer classes to avoid cluttering your models and make tests easier.

class ThingSerializer < ActiveModel::Serializer
  has_many :photos
  attributes :name, :whatever
end

# ThingsController
def index
  render :json => @things
end

# test it out
thing = Thing.new :name => "bob"
ThingSerializer.new(thing, nil).to_json
tee
  • 4,149
  • 1
  • 32
  • 44
1
format.json { render @things.to_json(:include => :photos) }
Darren
  • 1,235
  • 1
  • 8
  • 2
1

in case of array what I done is

respond_to do |format|
  format.html
  format.json {render :json => {:medias => @medias.to_json, :total => 13000, :time => 0.0001 }}
end
Bank
  • 1,783
  • 4
  • 17
  • 26