18

I'm a beginner in Rails and I have a problem with ActiveRecords associations.
I'm creating simple car rental service and I made the following associations:

class Client < ActiveRecord::Base
  has_many :rentals
  has_many :bookings
  has_many :cars, :through => :rentals
  has_many :cars, :through => :bookings
end

class Rental < ActiveRecord::Base
  belongs_to :client, dependent: :destroy
  has_one :car
end

class Booking < ActiveRecord::Base
  belongs_to :client, dependent: :destroy
  has_one :car
end

What I need is to have a car belonging to many bookings and rentals while every booking and rental can have only one car assigned.

class Car < ActiveRecord::Base
    # belongs_to_many :bookings
    # belongs_to_many :rentals
end

How should I do that?

Kamil Lelonek
  • 14,592
  • 14
  • 66
  • 90

3 Answers3

45

If a car can have many bookings/rentals, but a booking/rental can only have one car, you're looking at a classic belongs_to/has_many situation. It looks like you're being tripped up by the distinction between belongs_to and has_one -- it's not a grammatical one, but a matter of where the foreign key column is located in your database.

  • belongs_to: "I am related to exactly one of these, and I have the foreign key."
  • has_one: "I am related to exactly one of these, and it has the foreign key."
  • has_many: "I am related to many of these, and they have the foreign key."

Note that has_one and has_many both imply there's a belongs_to on the other model, since that's the only option where "this" model has the foreign key. Note also that this means has_one should only be used when you have a one-to-one relationship, not a one-to-many.

Taking this into consideration, I would replace the has_one :car with belongs_to :car in both your Rental and Booking models, and place has_many :bookings and has_many :rentals in your Car model. Also ensure that your rentals and bookings tables have a car_id column; there should be no rental- or booking-related columns in your cars table.

DigitalCora
  • 2,222
  • 1
  • 16
  • 24
  • That's what I figured out yesterday, but I needed a confirmation. Thanks for explaining it! – Kamil Lelonek Nov 25 '13 at 07:40
  • Is there a "I am related to many of these, and I have the foreign keys" relation? What is it? Thanks! – Ziggy Sep 11 '14 at 14:40
  • 3
    @Ziggy, there is no option that involves a model storing multiple foreign keys, since this isn't really possible using standard SQL column types. If you have a many-to-many relationship (e.g. posts have many tags, and tags have many posts), it should be represented by a third model (e.g. Tagging) in a [`has_many :through` configuration](http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association). – DigitalCora Sep 11 '14 at 21:09
  • 1
    plus one for a simple explanation - even useful to someone using a completely different programming language – Steve Feb 05 '15 at 17:17
2

Yes, there is a "belongs_to_many" in Rails, sort of. It's a little more work and you can't use generators with it. It's called a polymorphic association.

Even though you could make a car have many bookings & rentals, you could associate the car by making it belong to a polymorph such as rentable_vehicle. Your code would look like this

class Car < ActiveRecord::Base
  belongs_to :rentable_vehicle, polymorphic: true
end

class Rental < ActiveRecord::Base
  belongs_to :client, dependent: :destroy
  has_many :cars, as: :rentable_vehicle
end

class Booking < ActiveRecord::Base
  belongs_to :client, dependent: :destroy
  has_many :cars, as: :rentable_vehicle
end
Andrew
  • 546
  • 4
  • 17
0

You can't do belongs_to_many. The closest you can really get is has_and_belongs_to_many, but I'm not sure that's what you want here - unless you can have multiple cars per rental/booking. Check out the guide for a full explanation.

I'd change it up like this:

class Rental < ActiveRecord::Base
  belongs_to :client, dependent: :destroy
  belongs_to :car
end

class Booking < ActiveRecord::Base
  belongs_to :client, dependent: :destroy
  belongs_to :car
end

class Car < ActiveRecord::Base
  has_many :bookings
  has_many :rentals
end

Also, I don't know how your rentals relate to bookings, but my immediate thought is that there should be some relationship between the two, because you probably can't have a rental without booking it, right?

ussferox
  • 490
  • 5
  • 10