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 http://blog.antarestrader.com/?p=33 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