Hi --
Larry Kluger wrote:
Hi,
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?eg
Author
has_many :bookslarry = Author.find_by_name('larry', :include => :books)
ruby = larry.books.find_by_title('Ruby') # does this ALWAYS do a db
call?# Is the following the best way to get the one (or nil) book?
temp = larry.books.select{|book| book.title == 'ruby'}
ruby = temp.size == 1 ? temp[0] : nilThank you for your comments and time,
Larry
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
example:
$ ./script/console
Loading development environment.
>> f = Food.find(:first)
=> #<Food:0x3544f04 @attributes={"name"=>"bread", "id"=>"1",
"food_group_id"=>"2"}>
>> 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
performance.
David