On Feb 5, 10:29 am, Mike <[email protected]> wrote:
> 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?

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.

>   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' )

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 Jones

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en.

Reply via email to