has_and_belongs_to_manyメソッドを使って多対多のモデルの関連付けからレコードを作成するまでの手順を書いていきます。
記事執筆時のRailsとRubyのバージョンは以下のとおりです。
$ rails -v
Rails 6.0.3.1
$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin18]
has_and_belongs_to_many関連付け
has_and_belongs_to_many関連付けでは、多対多のモデルをつなぐ中間テーブルを作成します。has_many :through関連付けのように中間モデルは作成しません。
モデルの関連付けのイメージ図(Railsガイドから引用)
Active Record の関連付け - Railsガイド
assembliesとpartsが多対多で関連付けるモデルで、assemblies_partsがそれらの中間テーブルです。
モデルの関連付け
上記のモデルを以下のように具体化して説明します。
assembliesモデル→Userモデル
partsモデル→Bookモデル
assemblies_parts→books_usersテーブル
ユーザー(User)が読んだ本(Book)を登録するアプリを作成するとします。
1人のUserは複数のBookを登録でき、同じBookは複数のUserから登録されるため、多対多の関係になります。
UserモデルとBookモデルを関連づけるために、それぞれのモデルに以下の定義を追加します。
class User < ApplicationRecord
(中略)
has_and_belongs_to_many :books
end
class Book < ApplicationRecord
(中略)
has_and_belongs_to_many :users
end
UserとBookを紐づけるために中間テーブルを作成します。モデルは作成しないので、マイグレーションファイルのみ作成します。
rails g migration create_books_users book:references user:references
マイグレーションファイルが作成されるので、rails db:migrate
を実行します。
class CreateBooksUsers < ActiveRecord::Migration[6.0]
def change
create_table :books_users do |t|
t.references :book, null: false, foreign_key: true
t.references :user, null: false, foreign_key: true
end
end
end
レコードの作成
本(Book)を登録するアクションをコントローラーに作成します。
以下の例ではbuildメソッドでBookオブジェクトの作成、saveメソッドでBookオブジェクトをDBに保存、<<メソッドで中間テーブルにレコードを作成しています。
buildメソッド、<<メソッドはhas_and_belongs_to_manyで宣言したことにより使えるようになるメソッドです。
Bookオブジェクトの作成とDBへの保存の処理を分ける必要がない場合は、buildメソッドと<<メソッドの代わりにcreateメソッドを使ってオブジェクトの作成から保存までまとめて実行することもできます。
has_and_belongs_to_manyで追加されるメソッド - Railsガイド
class BooksController < ApplicationController
(中略)
def create
# 登録するBookのレコードに紐づけたい任意のUserオブジェクトをインスタンス変数に設定
@user = User.first
# Userと紐づくBookオブジェクトを作成(book_paramsはストロングパラメーター)
@book = @user.books.build(book_params)
# DBに保存
if @book.save
# 中間テーブルにレコードを作成
@user.books << @book
redirect_to @book
else
render :new
end
end
(中略)
end