Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: Eager loading as_json includes

  render :json => {
    "playlist" => playlist_description,
    "songs" => @playlist.songs.as_json(:include => {:playlist_songs => {:only => [:id, :position]}})
  }

The above code results in 1+N queries to the database, one to load playlist_songs for each song. The playlist is preloaded in @playlist.

This is so slow, how can I optimize?

like image 251
Johan Avatar asked Nov 28 '11 21:11

Johan


2 Answers

My guess: You're not eager-loading the playlist_songs at the moment. You're currently waiting until the as_json call - after which all the songs have been loaded - and then the code has to iterate over every song and fetch the playlist_songs then.

My guess (this is totally untested and may include bugs)

@playlist.songs.all(:include => :playlist_songs).as_json(:include => {:playlist_songs => {:only => [:id, :position]}})

AFAICT, this should first eager load all the songs and the playlist_songs... and then render as json.

like image 79
Taryn East Avatar answered Oct 15 '22 03:10

Taryn East


I would highly recommend integrating with a JSON builder such as rabl. It will make your life 10x easier moving forward, and is extremely nice to separate the "view" of the JSON representation. I made the switch a couple months ago and haven't looked back.

Within your controller:

@playlist = Playlist.where(:id => params[:id]).includes(:playlist_songs)

Then the rabl template could be something like this:

object @playlist
attribute :description
child :playlist_songs do
  attributes :id, :position
end
like image 35
ejlevin1 Avatar answered Oct 15 '22 02:10

ejlevin1