Rails belongs_to_many - ruby-on-rails

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?

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.

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

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?

Related

Is this database relation schema correct?

I made my first project and got into problem that I couldn't get the right category_information values for specific competitions category through relations. So I started thinking that this could be the wrong schema for this task, so my question - is it actually wrong?
Current Scheme:
Assuming the following relationships between models from your image.
class Competition < ApplicationRecord
has_many :categories
has_many :informations
has_many :category_informations, through: :categories
end
class Category < ApplicationRecord
belongs_to :competetion
has_many :category_informations
has_many :information, through: :category_informations
end
class CategoryInformation
belongs_to :catagory
belongs_to :information
end
class Information < ApplicationRecord
belongs_to :competetion
has_many :category_informations
has_many :catagory, through: :category_information
end
Model can relates with one_to_many_to_many using :through option
It explains a association used to set up a many-to-many connection with another model.
you can get the category_informations from competition like
Competition.first.category_informations
It is all for doing! Pretty good, right?
And you could do get information from category too
Category.first.informations
Actually wrong schema doesn't exist, just there exists some wrong association description.
You can get more usage to use association from docs at 2.3 section and 4.3 section
Assuming the following relationships between tables,
A competition has_many categories,
A competition has_many information,
A category has_many information,
A category has_many competition,
An information has_many category
You can use has_many_through relationships
class Category < ApplicationRecord
has_many :category_competitions
has_many :competitions, through: :category_competition
has_many :category_informations
has_many :informations, through: :category_informations
end
class Information < ApplicationRecord
has_many :category_informations
has_many :categories, through: :category_informations
end
class Competition < ApplicationRecord
has_many :category_competition
has_many :categories, through: :category_competitions
end
class CategoryCompetition < ApplicationRecord
belongs_to :category
belongs_to :information
end
class CategoryInformation < ApplicationRecord
belongs_to :category
belongs_to :information
end
By this way you can access,Categories of a particular competition by #competition.categories
This article might be helpful for you to understand associations better
https://www.sitepoint.com/master-many-to-many-associations-with-activerecord/

Rails type of relation between models

I have 3 models: User, Order and Car and I have question because I don't know what relationships between these models will be the best. Only requirement is that only one car per user in order.
A user can have many orders, and therefore, many cars through those orders.
class User < ActiveRecord::Base
has_many :orders
has_many :cars, through: :orders
end
An order belongs to a user and a car.
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :car
end
A car has one order.
class Car < ActiveRecord::Base
has_one :order
end
So you need one on one relationship between order and car and then back to order and customer one relationship. Something below should do the trick.
class Car < ActiveRecord::Base
has_one :order
has_one :customer, through: :order
end
class Order < ActiveRecord::Base
belongs_to :car
belongs_to :customer
end
class Customer < ActiveRecord::Base
has_one :order
has_one :car , through: :order
end
But i will suggest the has_many relationship by the looks of the model name, but you know better your problem than me.

What references, foreign_keys do I need to add for these associations?

I have these associations in my Rails 4.2 app. I don't understand how to setup the proper references/foreign_keys between instructors and courses.
So far both instructors and courses tables have a local_id (local reference).
Local is a training center they both belong to.
class Local < ActiveRecord::Base
has_many :instructors
has_many :courses
end
class Instructor < ActiveRecord::Base
belongs_to :local
has_many :courses, through: :locals
end
class Course < ActiveRecord::Base
belongs_to :local
has_many :instructors, through: :locals
end
Do I add a foreign_key to the courses table? Like this:
add_foreign_key :courses, :instructors
I read something about when having many to many associations we need a "join table" cause we need to store many ids. I guess Local is just that in this case.
Or do I need another table(Model) that belongs_to :instructor, :course?
Here is how I would set it up for maximum flexibility.
Instructors and Courses
Lets set up a many to many relationship with a join model which we call Employment.
We can generate the model with:
rails g model employment instructor:belongs_to course:belongs_to
Which will give us this:
class Employment < ActiveRecord::Base
belongs_to :instructor
belongs_to :course
end
employments will have the instructor_id and course_id foreign keys. This lets us assign any number of instructors to a course and vice versa.
So let's put the join model to use:
class Instructor < ActiveRecord::Base
has_many :employments
has_many :courses, through: :employments
end
class Course < ActiveRecord::Base
has_many :employments
has_many :instructors, through: :employments
end
Venues and Courses
I would recommend you rename your Local model Venue as it's the common english term for the place where a course or event is held. Locale is awkward since it collides with a separate concept in web applications and may cause name clashes.
And we should probably set it up as many to many to account for the complexities of real life.
So again:
rails g model booking venue:belongs_to course:belongs_to
class Booking < ActiveRecord::Base
belongs_to :venue
belongs_to :course
end
bookings will have the venue_id and course_id foreign keys.
class Venue < ActiveRecord::Base # was Local
has_many :bookings
has_many :courses, through: :bookings
end
class Course < ActiveRecord::Base
# ...
has_many :bookings
has_many :venues, through: :bookings
end
More reading:
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
http://blog.flatironschool.com/why-you-dont-need-has-and-belongs-to-many/

What is the correct rails model? Using redundancy recommended?

In my rails application Company acts as the user model. A company can have many customers and many employees (carseller).
There is a many to many relation between a carseller and a customer.
There is the following problem: A lot of times i'd have to retrieve all the appointments made with the whole company. Since there is no company_id saved in the appointment model this can be quite painful.
Should i just include a foreign key to company in the appointments and have some form of redundancy or is there another easy and efficient way?
class Company < ActiveRecord::Base
has_many :customers
has_many :carseller
end
class Customer < ActiveRecord::Base
belongs_to :company
has_many :appointments
has_many :carsellers, :through => :appointments
end
class Carseller < ActiveRecord::Base
belongs_to :company
has_many :appointments
has_many :customers, :through => :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :customer
belongs_to :carseller
end
I think you can use :
class Appointment < ActiveRecord::Base
belongs_to :customer
belongs_to :carseller
has_one :company, :through => :carseller
end
Then you just have to do appointment.company to get it.

Setting up a Has_Many :through Association

On the application I'm currently working on, I'm stuck on setting up the associations between 3 models to ensure referential integrity. I have an Event model, Building model, and a Room model. The association in real life is pretty intuitive. An Event can only be in one Building and one Room. A Building clearly can have multiple rooms.
Here's what I have set up now. However, how can Events specify their room if they belong to Buildings, and the foreign key for the Room is in the Events table? Is this where you use a has_many :through relationship? Is it good practice to store both the Building and Room foreign keys in the Event table, as Rooms are owned by Buildings? What about the conditional relationship that requires a building to be specified before allowing a room to be specified (some buildings have 2 rooms, others have 20, for example)
Sorry I'm so unclear on this. Thanks in advance for the help!
class Event < ActiveRecord::Base
belongs_to :building
end
class Building < ActiveRecord::Base
has_many :events
has_many :rooms
end
class Room < ActiveRecord::Base
belongs_to :building
end
I think the best way to handle this is to do something like the following:
class Event < ActiveRecord::Base
belongs_to :room
has_one :building, :through => :room
end
class Building < ActiveRecord::Base
has_many :events
has_many :rooms
end
class Room < ActiveRecord::Base
belongs_to :building
end
So you can use has_one :through to specify that an event owns a hotel
I would recommend the following:
class Event < ActiveRecord::Base
belongs_to :room
has_one :building, through: :room
end
class Building < ActiveRecord::Base
has_many :events, through: :rooms
has_many :rooms
end
class Room < ActiveRecord::Base
belongs_to :building
has_many :events
end
This way you can do #room.events, #event.building, #building.events

Resources