Ruby on Railsで中間テーブルの実装方法を探していませんか?
仕事で多対多の関係を避けるために中間テーブルを実装しましたが、ユニーク制約を注意深く付与しないと予期せぬトラブルを引き起こしかねません。
そこでこの記事では、実務経験をもとに中間テーブルの実装方法とユニーク制約の正しい付け方を解説します。
最後まで読めば、中間テーブルを正しく効果的に実装できるようになります。
この記事を書いているぼくは実務経験1年。独学で未経験から従業員300名以上の自社開発企業へ転職しました。実務ではVue.jsとRailsを毎日書いています。
中間テーブルを作る際はユニーク制約に注意しよう
手順は以下の2ステップです。
- マイグレーションファイルの作成と実行
- モデルファイル側でもユニーク制約を設定
順番に確認します。
1. マイグレーションファイルの作成と実行
まずは以下のコマンドでマイグレーションファイルを作成します。
$ rails g migration CreateBookmarks user:references job:references
中間テーブルのデータの組み合わせを一意にしたい場合、外部キーの組み合わせにユニーク制約をつけましょう(複合インデックス)
今回の場合、user_id と job_id のペアに対して設定します。
class CreateBookmarks < ActiveRecord::Migration[6.1]
def change
create_table :bookmarks do |t|
t.references :user, null: false, foreign_key: true
t.references :job, null: false, foreign_key: true
t.timestamps
end
add_index :bookmarks, [:user_id, :job_id], unique: true # ユニーク制約を設定
end
end
このマイグレーションファイルを実行すれば、データベース側にユニーク制約が設定されます。
$ rails db:migrate
2. モデルファイル側でもユニーク制約を設定
次にモデルファイル側でもユニーク制約を設定します。
以下はapp/models/bookmark.rb
の実装例です。
class Bookmark < ActiveRecord::Base
belongs_to :user
belongs_to :job
# scope付きでユニーク制約を設定
validates :user_id, presence: true, uniqueness: { scope: :job_id }
validates :job_id, presence: true
end
scope
を指定することで、user_id と job_id のペアが一意に限定されます。(片方だけでOK)
もしscope
を指定しなかったら、各ユーザは複数の求人をブックマークできなくなってしまうため、要注意です。
class Bookmark < ActiveRecord::Base
belongs_to :user
belongs_to :job
# scopeを指定しないと各ユーザはブックマークを2つ以上できなくなる
validates :user_id, presence: true, uniqueness: true
validates :job_id, presence: true
end
ユニーク制約をマイグレーションとモデルファイルの両方に書く理由
ユニーク制約はマイグレーションファイルとモデルファイルの両方に記述する必要があります。
この点については、以前にも疑問に思ったため、次の記事にまとめてあります。
まとめ
この記事では中間テーブルの実装方法と、データの組み合わせを一意としたい場合の注意点をまとめました。
ユニーク制約をつけ忘れて後から追加でマイグレーションを実行するのはとても面倒です。
この記事のやり方をしっかり覚えておきましょう。
また、以下の記事ではワンランク上のRailsエンジニアになりたいと考えている方向けにおすすめの技術書を紹介しています。
こちらの記事もぜひ読んでみてください。
コメント