Rails belongs_to_many

Kamil Lelonek picture Kamil Lelonek · Nov 25, 2013 · Viewed 9.1k times · Source

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?

Answer

DigitalCora picture DigitalCora · Nov 25, 2013

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.