Rails の マイグレーションと references について
Rails のマイグレーション機能で使える、references は簡単にリレーション用のカラムを追加することができるものです。
例えば…
User モデルと Article モデルというのがあったとします。
class User < ApplicationRecord
has_many :articles
end
class Article < ApplicationRecord
belongs_to :user
end
こういう状態の時 migration ファイルで
def change
create_table :articles do |t|
t.string :title # 記事タイトル
t.text :body # 記事本文
t.references :user
end
end
こうすると articles テーブルに user_id カラムが追加されます。
user_id カラムが追加されるので、user_id 明記して書くのとほぼ同義ですね。
def change
create_table :articles do |t|
t.string :title # 記事タイトル
t.text :body # 記事本文
t.integer :user_id
end
end
「ほぼ」と書いたのは、references と使った場合は追加した user_id カラムに対して index を自動で作ってくれるのですが、 user_id を直接書いた場合は index は自分で追加する命令を書かないといけません。
index が何者かという説明は難しいのですが、データベースの検索のパフォーマンスをあげるために必要な仕組みという理解でとりあえず大丈夫です。
index があってもなくても同じ挙動をしますが、データ量が増えてきた場合にパフォーマンスに影響が出てくるようになります。
references の他の仕組み
references にはカラムをただ追加するだけでなく、いくつかオプションがあります。
その中の一つが foreign_key の指定です。
t.references :user, foreign_key: true
とすることで、追加したカラムに対して外部キー制約をつけることができます。
外部キー制約はRails の機能というよりは MySQL や PostgreSQL といったデータベース側の機能で、外部キー制約を使うことで、データの構造をより厳格にすることができるようになるので、こうしたリレーションをさせるための id に対しては基本的にはつけた方が良いです。
ただし、外部キー制約があると困るパターンもあるのでどういう挙動をするのかというのは理解した上でつけるべきです。
例えば…
ユーザーが投稿した記事は、ユーザーが退会してもそのまま残したい。
ということを考えている場合に…
先ほどの User モデルと Article モデルを例で、articles テーブルの user_id に対して外部キー制約をつけてみます。
def change
create_table :articles do |t|
t.string :title # 記事タイトル
t.text :body # 記事本文
t.references :user, foreign_key: true
end
end
外部キー制約をつけたので、articles テーブルの user_id のユーザーは必ずデータとして存在していなくてはなりません。
そんな中ユーザーが退会して users テーブルのデータを消そうとすると、外部キー制約でエラーになってしまいます。
エラーにならないようにするためには、user を消す前に user にひもづく article を全て消さなければなりません。
そうすると、最初に書いた
ユーザーが投稿した記事は、ユーザーが退会してもそのまま残したい。
というのが実現できなくなってしまうので、こうした場合は外部キー制約はつけてはいけない、ということになりますね。