I need to do some initialization on instances that involve an
associated model.
This means that when I find an object, it immediately does another
query to get its association.
To cancel the double query, I make sure the associated model gets pre-
loaded by using :include when retrieving the object.
Only, it seems that after_initialize or after_find get triggered
before activerecord does its associating-trick.
No matter what I try, finding the object always triggers another
query.
I guess this has to do with the order callbacks get called.
Is there any way to circumvent this?
Like I said, I tried that, it doesn't work in this case.
My guess is that in after_find the associations aren't loaded yet
(they are included in the query, but they aren't parsed yet).
A quick pass through the ARec code suggests that after_find does not
introduce the kinds of double-queries that you're talking about. Any
time the :include option is passed into #find the call is delegated to
ARec::Associations#find_with_associations. That method retrieves
records using a join and then calls instantiate on each record.
Instantiate, in turn, calls after_find and after_initialize as the
last two steps before returning the object to the caller. This was
only a cursory look on my part but it does not appear that there are
any chances for associations to be loaded later.
If you post the code in question we can probably be of more
assistance.
here is some example code(stupid example but it does the trick):
create_table "people", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "pets", :force => true do |t|
t.string "name"
t.string "kind"
t.string "person_id"
t.datetime "created_at"
t.datetime "updated_at"
end
class Person < ActiveRecord::Base
has_many :pets
end
class Pet < ActiveRecord::Base
belongs_to :person
attr_accessor :fullname
def after_find
self.fullname = "#{person.name}'s #{kind}"
end
end
now when I do this:
Pet.find(:first, :include => :person)
I get this in my log:
Pet Load Including Associations (0.000385) SELECT pets."id" AS
t0_r0, pets."name" AS t0_r1, pets."kind" AS t0_r2, pets."person_id" AS
t0_r3, pets."created_at" AS t0_r4, pets."updated_at" AS t0_r5,
people."id" AS t1_r0, people."name" AS t1_r1, people."created_at" AS
t1_r2, people."updated_at" AS t1_r3 FROM pets LEFT OUTER JOIN people
ON people.id = pets.person_id
Person Load (0.000249) SELECT * FROM people WHERE (people."id" =
1)
So it appears after_find still insists of loading the person, which
was already loaded by :include => :person