Ask A Question

Notifications

You’re not receiving notifications from this thread.

How to model these relations in Rails

Drazen asked 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?

Reply

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

Reply

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.

Reply

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?

Reply

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.

Reply

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
Reply

Thank you!

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 86,946+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.