Skip to main content

How to model these relations in Rails

Rails • Asked by Drazen Mokic

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


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 22,346+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.