HABTM and has_one with STL

Hi,

I have an interesting dilemma, which is best shown through example.
Say I have Car and Part models which have a HABTM association. In
this case though, the Part class is an STL with Wheel and
SteeringWheel as models. Is there a way to setup the Car model with
both HABTM and has_one relationships to the same table?

class Part < ActiveRecord::Base
has_and_belongs_to_many :cars
end
class Wheel < Part
end
class SteeringWheel < Part

do I put a new association here?

end

class Car < ActiveRecord::Base
has_and_belongs_to_many :cars
has_one :steering_wheel
end

This way, I could do something like so:

car = Car.new
car.wheels << Wheel.new( :brand => ‘Dunlop’)
car.wheels << Wheel.new( :brand => ‘Dunlop’)
car.wheels << Wheel.new( :brand => ‘Bridgestone’ )
car.wheels << Wheel.new( :brand => ‘Bridgestone’ )
car.steering_wheel = SteeringWheel.new( :brand => ‘Sparco’ )

On Feb 5, 10:29am, Mike [email protected] wrote:

end
class Wheel < Part
end
class SteeringWheel < Part

do I put a new association here?

You’d need to declare ‘belongs_to :car’ and add a corresponding car_id
field to the parts table.

end

class Car < ActiveRecord::Base
has_and_belongs_to_many :cars

I’m guessing this is a typo, as you’ve got it as ‘wheels’ below.

car.steering_wheel = SteeringWheel.new( :brand => ‘Sparco’ )
I’m not sure how useful the “car” analogy is here; it carries quite a
bit of semantic baggage that may not apply to your real problem
domain. Some notes about it anyways:

  • are the records in the ‘Part’ table intended to represent a single
    instance of a particular part or the generic class of all similar
    parts? It’s unclear from the example above, as every instance of Car
    needs a different SteeringWheel record (has_one/belongs_to can only
    link one pair of records) but Car instances can share Wheels. In code:

car1 = Car.new
car2 = Car.new
wheel = Wheel.new(:brand => ‘Foo’)
steering_wheel = SteeringWheel.new(:brand => ‘Bar’)

car1.wheels << wheel
car1.save
car2.wheels << wheel
car2.save
car1.wheels.first # => some Wheel object
car2.wheels.first # => some Wheel object with the same ID as the first

so no problems there

car1.steering_wheel = steering_wheel
car1.save
car2.steering_wheel = steering_wheel
car2.save

and the gotcha:

car1.reload
car1.steering_wheel # => nil


The other big issue with using STI here is that there really aren’t
that many properties in common between the two entities -
manufacturer, perhaps? There certainly aren’t many places where one
could interchangeably use a steering wheel or a regular wheel…

Again, this may be a specific issue with the “car” example, but it’s
worth checking into. If there’s some overlap but a lot of difference,
you may want to consider factoring the overlap into a module and
avoiding the “everything and the kitchen sink” table that STI can lead
to if used inappropriately.

–Matt J.