1

I am building out a rails 5 ruby 2.4.0 app.

I have a Truck model, and a User model.

I would like to reference several users to the truck.. the person who created the truck, the owner of the truck and the driver of the truck if it differs from that of the owner. I want it to reference only the user because I don't want to have may types of user models.

Is this theoretically possible?

im thinking about this:

Truck has_many_users

user belongs_to truck (not sure how to work this?)

when a truck is created it logs the current user id, then the user can select system users for the driver association and owner association...

Please help i'm burning my brain trying to map this out..

Shawn Wilson
  • 1,311
  • 14
  • 40
  • Yep, it's possible -- see https://stackoverflow.com/questions/4516416/belongs-to-and-has-many-to-the-same-model – wolfson Apr 02 '18 at 02:30

1 Answers1

2

So what you're looking for is associating Truck to User multiple times, with each association playing a different role.

It's definitely possible, and quite a common way to set up associations.

However, I would definitely set it up so that the Truck model is the child ("belongs to") the User model, for two reasons -

  1. A truck model should be self-contained in its knowledge. It should know who its creator, driver, and owner are. So you want those id's (foreign key references) stored on the Truck and not the User. Also in your case each truck can have 1 and only 1 creator, driver, or owner. (Side note: If you did have a case where a Truck could have numerous creators, drivers, and owners then this wouldn't work and you'd have to rely on a many-to-many relationship like an intermediary joining table.)

  2. A user can inherently be associated with multiple trucks. A user could own 3 different trucks or they could own 1 truck but drive another. It makes more sense that a User would have the has_many relationships here.

The trick is that ActiveRecord lets you name associations anything you want. So you can try -

class Truck < ApplicationRecord
  belongs_to :creator, class_name: "User", foreign_key: :creator_id
  belongs_to :owner, class_name: "User", foreign_key: :owner_id
  belongs_to :driver, class_name: "User", foreign_key: :driver_id
end

class User < ApplicationRecord
  has_many :created_trucks, class_name: "Truck", foreign_key: :creator_id
  has_many :owned_trucks, class_name: "Truck", foreign_key: :owner_id
  has_many :driven_trucks, class_name: "Truck", foreign_key: :driver_id
end

In each line we override -

  1. The class_name, because if we didn't specify it Rails would use the associated name to guess it. So belongs_to :creator would look for a Creator model, instead of a User model

  2. The foreign_key, because if we didn't specify it Rails would use the associated name to guess it. So belongs_to :creator would look for for a creator_id on this model (since it belongs to the other model). Similarly if we had has_one :creator it would look for a creator_id on the foreign Creator model (or whatever is specified via class_name).

user2490003
  • 10,706
  • 17
  • 79
  • 155
  • It seems like some explanation and part of the process is missing here. Usually when you point to a foreign key, it's looking for the column that you specify in the table you link to via `class_name` right? So if both Truck and User are pointing to the foreign key of `:creator_id`, in which table does that column actually exist? Both? Neither? How exactly would this scenario be used in a pair of related tables? Can you explain what else you would do to actually make it work? – AFOC May 02 '18 at 16:18
  • The Rails docs for `belongs_to` and `has_many` mention that "By default [the foreign key] is guessed to be the name of the association with an “_id” suffix". So it uses the association name (`:creator`) and NOT the class name `User`. In the case of `belongs_to`, Rails looks for a foreign key column named `:creator_id` on THIS table (`Truck`). In the case of `has_many`, Rails looks for a foreign key column named `:creator_id` on the OTHER table (also `Truck`). It knows the "other" table's name by looking at the association name or you can also specify it explicitly (`class_name: "Truck")`. – user2490003 May 03 '18 at 17:35
  • Thanks for the clarification on where the foreign key is being sought in each case. By this logic then, isn't it unnecessary to put any of those foreign key declarations in `Truck`? Rails will automatically look for each of those correctly based on the association name right, by tacking on `_id`? It only actually needs `class_name: 'User'` to reference it to the right table. – AFOC May 03 '18 at 19:00