Eager loading objects in a Rails has_many :through association

January 4, 2007 · 1 comment

in Ruby on Rails

I’m still working on the Rails application that was the source for this tutorial — which loads of developers who I really respect keep linking to, so I must have done something right there!

Anyway, I’m going to blog this bit of code in the hope that it will help me remember it.

As stated before, I have Production and Venue objects, which are linked by means of intermediary Run objects. Minimal code:

class Production < ActiveRecord::Base
  has_many :runs
  has_many :venues, :through => :runs
end

class Venue < ActiveRecord::Base
  has_many :runs
  has_many :productions, :through => :runs
end

class Run < ActiveRecord::Base
  belongs_to :production
  belongs_to :venue
end

Now, when listing the productions, I need to display a small amount of information about when and where each production is on. The rules that determine what get displayed vary, and aren’t particularly relevant to the discussion here. What matters to me is that, when listing (say) 20 productions, with run and venue information included, all the data is collected in a single SQL query.

As with standard joins, you can use the find method’s :include option to include associated objects within the query. But I wasn’t having much luck pulling in both the runs and the venues: the runs would be detected, but iterating through the productions would trigger a fresh SQL query to find the relevant venue information.

Today, I found what I had to do to get it to work. The format for the find needs to be:

@productions = Production.find(:all, ... , :include => {:runs => :venues})

Lo and behold, all the requisite data is collected in a single query, which substantially cuts down on the page load time on my development box.

I’m not quite sure why the hash works — or, to be honest, how I stumbled upon the solution: I’ve been scouring the internet all day, yet for some reason I can’t find the page in my browser history. All I know is that it’s not an approach I’d have stumbled upon myself, as it’s not necessarily as intuitive as most ActiveRecord code is. However, there is a certain elegance to it, with the hash’s arrow symbolising the relationship from one object type to the next, which should hopefully enable me to remember the construction in future.

Related posts:

  1. Rails: ActiveRecord goes :through
  2. New Rails feature: simply_helpful
  3. A curious case of spam traffic
  4. Wordpress Wednesday: Efficient Related Posts
  5. Wordpress Wednesday: Custom Post Limits

{ 1 comment… read it below or add one }

1 Marcio April 28, 2008 at 9:45 am

Thanks for sharing! I had exactly the same problem and I tried your hash thing in my :include and it worked! Really tricky concept to understand, specially when I was browsing articles and tutorials and didn’t really find anything explaining the hash use in :include, only superficial things. Thanks!!

Reply

Leave a Comment

Previous post:

Next post: