find_by_ always uses sql?

Hi --

Larry Kluger wrote:


If I eagerly load a collection during the initial find, do scoped
find_by_ calls later _always_ use sql?

What is the best pattern to use to not do another db trip?
Is there some specialized rails method to handle this case?

  has_many :books

larry = Author.find_by_name('larry', :include => :books)

ruby = larry.books.find_by_title('Ruby') # does this ALWAYS do a db

# Is the following the best way to get the one (or nil) book?
temp ={|book| book.title == 'ruby'}
ruby = temp.size == 1 ? temp[0] : nil

Thank you for your comments and time,


Sense you now have all Larry's books in memory it is probably better to
search through the memory using ruby calls like:

ruby = larry.books.detect {|book| book.title == 'ruby'}

find and find_by_* on a collection are smart, though: they get rolled
into one database query with the collection query itself. For

   $ ./script/console
   Loading development environment.
   >> f = Food.find(:first)
   => #<Food:0x3544f04 @attributes={"name"=>"bread", "id"=>"1",
   >> f.ingredients.find_by_description("flour")
   => #<Ingredient:0x3523c28 @attributes={"id"=>"3",
   "description"=>"flour", "food_id"=>"1"}>

Here's the query log:

   Food Load (0.000726) SELECT * FROM foods LIMIT 1
   Ingredient Load (0.000394) SELECT * FROM ingredients WHERE
   (ingredients.food_id = 1) AND (ingredients."description" = 'flour')
   LIMIT 1

Notice how the second select combines two where clauses, so the whole
collection isn't loaded into memory.

The find_by_* methods have some overhead, though, since they have to
pass through method_missing. You can also do:

   f.ingredients.find(:first, :conditions => "description = 'flour'")

which won't have that overhead. Of course, find_by_* is nice and
concise, so it's OK for cases where you're not looking to tweak