Ruby on Rails: Many-to-many relationship on the same table as a one-to-many relationship

36 views Asked by At

I am learning Ruby on Rails and am currently struggling to implement a many-to-many relationship. I have a user and a carpool that can be driven by a user and ridden by multiple users. So, I am trying to implement a join table carpools_users with has_and_belongs_to_many. I assume there is something wrong with my models but I can't figure out what I am doing wrong exactly.

Currently a RuntimeError gets thrown because i am violating a not null constraint of carpools_users.carpool_id .

Migrations

20230621132948_create_carpools.rb

class CreateCarpools < ActiveRecord::Migration[7.0]
  def change
    create_table :carpools do |t|
      t.references :driver, foreign_key: { to_table: 'users' }
      t.references :passenger, foreign_key: { to_table: 'users' }

      t.timestamps
    end
  end
end

20230621123159_create_users.rb

class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :name
      t.references :ridden_carpool, foreign_key: { to_table: 'carpools' }
      t.references :driven_carpool, foreign_key: { to_table: 'carpools' }

      t.timestamps
    end

    create_join_table :users, :carpools, :id => false
  end
end

Models

carpool.rb

class Carpool < ApplicationRecord
  belongs_to :driver, :class_name => 'User', :foreign_key  => "driver_id"
  has_and_belongs_to_many :passenger, :class_name => 'User', :foreign_key  => "user_id"
end

user.rb

class User < ApplicationRecord
    has_many :driven_carpools, :class_name => "Carpool", :foreign_key  => "driven_carpool_id"
    has_and_belongs_to_many :ridden_carpools, :class_name => "Carpool", :foreign_key  => "carpool_id"
end
1

There are 1 answers

0
Rafael Moreira On

Inside your CreateUser, in this line, the :id => false, I don't think it is necessary. When you create a join table, the table will have 2 columns with the id of each model you included by default, and that's it. Check here create_join_table and here Create Join Table

create_join_table :users, :carpools

In your CreateCarPool, I believe you have many passengers, so passenger should be in the plural.

t.references :passengers, foreign_key: { to_table: 'users' }

Also in CarPool, on his line, passenger should be plural.

has_and_belongs_to_many :passengers, :class_name => 'User', :foreign_key  => "user_id"

Maybe in your User model you going to update the foreign_key on the has_many and also add the join table to the has_and_belongs relationship. The foreign_key for your user in CarPool is driver_id, that's the one which you used to associate.

class User < ApplicationRecord
  has_many :driven_carpools, class_name: "Carpool", foreign_key: "driver_id"
  has_and_belongs_to_many :ridden_carpools, class_name: "Carpool", join_table: "carpools_users", association_foreign_key: "carpool_id"
end

Another thing is. I don't know in which order you creating these tables and updating your models, but you need to follow first with User, basic CarPool, rails db:migrate, then go for updating your models, always remembering to migrate after changes. For na ID to be used, you first need to migrate before going to next step.