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 Nakajima 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 Antares Trader for My Humble Opinion)

Pat Nakajima 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:

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