How to model these relations in Rails
For a couple of days now i am going back and forth how to models this.
I currently have the following model structure and relations (simplified)
class Fleet < ApplicationRecord
# properties id, created_at, updated_at
# A fleet should only consists of the same type, either a fleet or cars or a fleet of trains. Never both
has_many :cars
has_many :trains
end
class Car < ApplicationRecord
# properties id, created_at, updated_at, number_of_gears, is_sports_car
belongs_to :fleet
end
class Train < ApplicationRecord
# properties id, created_at, updated_at, number_of_wagons, people_capacity, has_first_calass_section
belongs_to :fleet
en
The problem i have is thata fleet should only consists of the same type, either a fleet of cars or a fleet of trains. Never both.
With the current relations on fleet, it seems error prone to have both has_many associations (or more coming like Airplanes) in terms of integrity and ease of use when calling @fleet._cars-or-trains, i would have to know what i can call.
STI is not an option since the properties are very different on a Car and a Train. There are many more properties, for the sake of simplicity i have shortened them in this example.
What is the right way in Rails to do this?
Have you looked at Multiple Table Inheritance? Seems like it might work.
This gem makes it really easy: https://github.com/krautcomputing/active_record-acts_as
I would probably just add a fleet_type
column to the fleet that keeps track of which is allowed: Train
Car
, etc. Then you can use it for validation against the associated models to make sure they're of the correct type.
Hi Chris,
is this something Rails has built in or would i need to set the fleet_type manually by checking if a Car or Train was created?
Not built-in. You could set it before_create and check the first child model type and use that, and also validate that they're all the same type.
Here's some quick psuedo code:
class Fleet
has_many :cars
has_many :trucks
validate :same_type
before_create do
self.fleet_type = "Car" if cars.exists?
self.fleet_type = "Truck" if trucks.exists?
end
private
def same_type
if cars.exists? && trucks.exists?
errors.add(:base, "All items in fleet must be of the same type")
end
end
end