Caching reverse associations in ActiveRecord

Let’s say we have two models with a plain has_many/belongs_to
relationship.

class Driver
has_one :car
end
class Car
belongs_to :driver
end

The question is this: Why isn’t the car’s parent driver cached when
we
eager load it? So the following snippet (as impractical as it is,
it’s
just an example) would just result in one hit (as opposed to
ActiveRecord’s current behavior, which hits the db each time that
#driver is called).

@driver = Driver.find(:first, :include => :car)
@driver.car.driver.car.driver.car.driver.car

Is there a reason for the current behavior?

Pat N. wrote:

Let’s say we have two models with a plain has_many/belongs_to
relationship.

class Driver
has_one :car
end
class Car
belongs_to :driver
end

The question is this: Why isn’t the car’s parent driver cached when
we
eager load it? So the following snippet (as impractical as it is,
it’s
just an example) would just result in one hit (as opposed to
ActiveRecord’s current behavior, which hits the db each time that
#driver is called).

@driver = Driver.find(:first, :include => :car)
@driver.car.driver.car.driver.car.driver.car

Is there a reason for the current behavior?

Yep, you’re correct, this is silly, and a known deficiency in
ActiveRecord. Usually, this comes up in situations where you are
calling a method on car from a method in driver. The method in Car in
turn needs some information about Driver. The quick fix for this is to
send a reference to Driver to the method in Car instead of having the
car rely on it’s one #driver method:

class Driver < ActiveRecord::Base
has_one :car
def some_driver_method
self.car.some_car_method(args,self)
end
end

class Car <ActiveRecord::Base
belongs_to :driver
def some_car_method(args,dvr=self.driver)
dvr.some_attribute
end
end

If this seems like a hack, it is. You might also checkout DataMapper
(http://datamapper.org/) which solves this problem, but is not really
mature enough, IMHO. (see http://blog.antarestrader.com/?p=33 for My
Humble Opinion)

On 7 Feb 2008, at 19:05, Starr T. wrote:

end
@driver.car.driver.car.driver.car.driver.car

You could also manaually set the association target. I suppose that in
general it is non trivial to figure out which association (or even
associations) is the reverse association (especially with more
complication associations using conditions etc…).

Fred

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs