Topic: :include two level deep

I'm using the :include directive to find the associated objects for an Artist.

Artist.find(:all, :include => [:news, :shows, :releases])

Very cool.

But, I also need to include the tracks for each release (Artist has_many Releases. Release has_many Tracks).

Is this possible keeping just that one-liner, or do I need to add some more code?

Here's some invalid code to demonstrate what I need:

Artist.find(:all, :include => [:news, :shows, [:releases, :include => :tracks]])

I thought about how mothers feed their babies with tiny little spoons and forks, so I wondered what do Chinese mothers use. Toothpicks?

Re: :include two level deep

Include does not define the association. It controls whether AR performs "eager loading" of that particular association. So, if you have a Disc model, and a Track model, and Disc has_many tracks, you can do:

disc = Disc.find :all
discs.each{|disc| disc.tracks.each{|track| puts "Disc #{disc} : Track #{track}}

which boils down to:

select * from discs;
select * from tracks where disc_id=1;
select * from tracks where disc_id=2;
select * from tracks where disc_id=3;
select * from tracks where disc_id=4;
...

AR will, by default use lazy loading, where the primary data is loaded, but not the associations. However, as you access the association, a secondary SQL query is issued to load the tracks if necessary. We all know this can be done in one query, which is where :include comes into play:

disc = Disc.find(:all, :include => :tracks)

This boils down to:

select *.discs, *.tracks from tracks where tracks.disc_id = discs.id;

And with no further ado, you can iterate the list of discs and their associated tracks without another round trip to the database. However...

What if each Track could have different musicians (i.e., Track has_many :musicians). It would stand to reason that you could somehow tell AR that you want to continue the join process; however, that's not how the syntax is carved out. Once you get beyond that first eager load, you will begin lazy loading, and that's probably a good thing, as loading all the musicians for all the tracks on all the discs could consume a lot of resources. If that's really what you want to do, I believe it can be accomplished using :joins.

Re: :include two level deep

Found it!

I thought about how mothers feed their babies with tiny little spoons and forks, so I wondered what do Chinese mothers use. Toothpicks?

Re: :include two level deep

For those who didn't follow the link, jed.hurt's code looks something like this now:

Artist.find(:all, :include => [:news, :shows, {:releases => :tracks}])

Re: :include two level deep

Righto. Sorry, I should have clarified smile

I thought about how mothers feed their babies with tiny little spoons and forks, so I wondered what do Chinese mothers use. Toothpicks?

Re: :include two level deep

cwd, that was also very informative and helpful (at least to me), thanks.

Re: :include two level deep

Kelli wrote:

cwd, that was also very informative and helpful (at least to me), thanks.

If this was informative to you, does that mean that you've decided to go ahead and dive in and learn Ruby and Rails?

I thought about how mothers feed their babies with tiny little spoons and forks, so I wondered what do Chinese mothers use. Toothpicks?