Michael Kovacs' photos More of Michael Kovacs' photos
Recommend Me Cable Car Software logo

Thursday, August 17, 2006

Rails realities part 17 (Prefetching and using :joins)

Been awhile since I've posted but I actually have some cool stuff to talk about shortly when I get more time as I've been quite busy. But today is a quick post about using finders, namely prefetching and joins. Not much is written on the topic or when you might want to use some of the various options on on a find method.

First off the problem statement. We have a page where we display a list of Foo objects. We also have a relation on Foo called 'notes'. What we want is to pre fetch the related notes objects that have not been read.
We'll start off building our query from ground zero.

So the query starts off like this:

@foos = Foo.find(:all)
This simply gives us our list of all foos.

Next we move up to including the 'notes' relation
@foos = Foo.find(:all, :include => :notes)
OK so now we're prefetching notes, but we're getting all of them and we only want the ones that have not been read. How are we going to do that? Conditions? Let's try that:
@foos = Foo.find(:all, :include => :notes, :conditions => ['notes.read = 0'])
What this will return is the list of Foo objects that have unread notes. Hmm... not what we want. We want all Foo objects but we want to prefetch the ones that have not been read.

OK how about this clever hack... We create a new relation on Foo for the purpose of fetching related objects that meet this criteria? Note: This is NOT an ideal solution but in the interest of simply getting it working sometimes you shoot first and ask questions later. So we add the following to Foo and modify our finder query as follows:
class Foo
has_many :unread_notes, :conditions => 'read = 0'
@foos = Foo.find(:all, :include => :unread_notes)
Sure enough, this does what we want, but now we've got a relation on Foo whose sole purpose is life is to run this query. I mistakenly thought that the :joins parameter would do what I want but thusfar that's proven not to be true. So as of right now I have a dummy relation in my object so that I can prefetch intelligently. Is there a "correct" way to perform this in my finder query?


Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?