Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 5: Add record to join table without model (has_and_belongs_to_many)

I have a User and MeetOption table. This is a many-to-many relationship, and I was able to create a join table using the create_join_table command:

rails g migration CreateJoinTableUsersMeetOptions users meet_options

This generated a migration file:

class CreateJoinTableUsersMeetOptions < ActiveRecord::Migration[5.0]
  def change
    create_join_table :users, :meet_options do |t|
      # t.index [:user_id, :meet_option_id]
      # t.index [:meet_option_id, :user_id]
    end
  end
end

I also created the association between user and meet_option models using has_and_belongs_to_many

class User < ActiveRecord::Base
  has_and_belongs_to_many :meet_options
#More codes below
end

class MeetOption < ApplicationRecord
  has_and_belongs_to_many :users
end

The association works fine, and I can query for example, user.meet_options in Rails console.

My question is: there is no model for the joined MeetOptionsUsers table, so how can I add records to it? Right now, I have to manually add rows, i.e. user_id = 1; meet_option_id = 2, using a GUI database software (Postico).

Is there a way to add records such as MeetOptionUser.create(user_id: 1, meet_option_id: 2) in Rails console, just like when there's an ActiveRecord model associated with it?

like image 919
Daniel Avatar asked Nov 05 '17 20:11

Daniel


1 Answers

With a has_and_belongs_to_many relationship, you should be able to use normal Active Record association methods to link your Users and MeetOptions together. You should not need to manipulate the join table directly. Rails takes care of that for you. The Ruby on Rails Guide has_and_belongs_to_many Association Reference lists all of the useful methods automatically created by this association.

Here are some methods you may find useful.

The collection<<(object,..) will add one or more objects to the join table. For example:

@user.meet_options << @meet_option

The above will associate provided @meet_option record with @user by adding the appropriate entry in the join table. In this case, a record with user_id: @user.id and meet_option_id: @meet_option.id will be added to the join table. The reverse accomplishes the same thing:

@meet_option.users << @user

Another useful method is collection.delete(object,...). This allows you to remove associations from the join table. It does not delete the associated objects. For example:

@user.meet_options.delete @meet_option

The above will remove the association between @user and @meet_option by deleting the appropriate record from the join table. However, it does not delete @user from the users table, nor does it delete @meet_option from the meet_options table.

collection.destroy(object,...) does pretty much the same thing as collection.delete(object,...).

collection=(objects) will make the collection contain only the supplied objects by adding or deleting from the join table as required.

There are many other using methods in this association. I recommend reviewing the linked guide. Using these methods, you should be able to manage the join table without manipulating it directly. Let Rails and Active Record do the work for you.

Final Thought

If you want to have more direct access to the join table via a join model, the you should not use the has_and_belongs_to_many association. Perhaps you want to add more attributes to your join table or you want to have validations or callbacks on the join model itself. In this case, you should use a has_many :through association instead. This blog post walks through how to set that up.

like image 148
Tom Aranda Avatar answered Nov 09 '22 14:11

Tom Aranda