株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。
DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら弊社HPからご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。
- プロジェクトでRailsエンジニアが足りなくて困っている
- Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
- オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい
また、Railsエンジニアも募集しておりますので、興味がありましたら弊社HPからご連絡いただけますと幸いです。
前提
Railsで外部キーのカラムを追加する際に、reference型を使うことがあると思います。
reference型の使い方に関しては以下のように様々な記事があります。
外部キーをreferences型カラムで保存する
Rails4 外部キーをテーブルに設定するための、3通りのマイグレーションの書き方。
しかし、reference型で作成する時はadd_index: true
必要なの?foreign_key
必要なの?
と混乱してしまうので、備忘録のためにまとめておきます。
前提
アプリケーションとしてはTwitterの簡易版で、登録しているユーザーがツイートができるアプリケーションです。
テーブル構造としては
user : tweet = 1 : N
の関係になっています。
テーブル名はそれぞれ、users
とtweets
です。
reference型を使わない場合
まずはreference型を使わないで、外部キー制約のついたカラムを作成します。
制約などなにもないカラムの作成
以下のように記述すると、インデックスが貼られない、外部キー制約もつかないカラムを作成することができます。
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.integer :user_id
end
end
end
インデックスを貼るカラムの作成
インデックスを貼る場合、2通りの書き方があるようです。
インデックスとはなんぞやという方は こちら をご覧ください。
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.integer :user_id, index: true #indexオプション
end
end
end
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.integer :user_id
end
add_index :tweets, :user_id
# add_index :対象のテーブル名, インデックス対象のカラム名
end
end
外部キー制約が付いているカラムの作成
reference型を使わない場合、foreign_key: true
では外部キー制約にならないので注意が必要です。
また、外部キー制約をつける場合、インデックスは自動で付与されるので、先ほどのindex: true
は不要になります!(便利ですね)
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.integer :user_id
end
add_foreign_key :tweets, :users
# add_foreign_key :対象のテーブル名, :指定先のテーブル
end
end
reference型を使う場合
次に、reference型を使う場合の外部キー制約のついたカラムを作成します。
reference型を使うメリット
reference型を使い、t.reference :user
と記述すると2つのメリットがあります。
-
user
ではなくuser_id
というカラム名を作成してくれる - インデックスを自動で張ってくれる
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.references :user
end
end
end
しかし、t.reference :user
だけでは外部キー制約はつきません。
ですので、reference型を使う場合は以下のように記述して、外部キー制約をつけることになります。
reference型では外部キー制約をつけるときに、foreign_key: true
が使えるようになります!
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.references :user, foreign_key: true
end
end
end
ちなみに以下のようにadd_foreign_key
でも大丈夫です。
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.references :user
end
add_foreign_key :tweets, :users
end
end
まとめ
外部キー制約のついたカラムを作る際は、以下のように記述するのが手っ取り早いです。
class CreateTweets < ActiveRecord::Migration[5.0]
def change
create_table :tweets do |t|
t.string :text
t.references :user, foreign_key: true
end
end
end
ちなみにadd_column
の場合は以下の形が手っ取り早いです。
class AddColumn < ActiveRecord::Migration[5.0]
def change
add_reference :tweets, :user, foreign_key: true
end
end
追記
紐付き先のテーブル名とカラム名に別名にしたい場合は以下のようになります。
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :teams do |t|
t.bigint :owner_id, index: true
end
add_foreign_key :tweets, :users, column: :owner_id
end
end
class AddColumnToUsers < ActiveRecord::Migration[5.0]
def change
add_reference :tweets, :owner, foreign_key: { to_table: :users }
end
end
参考にしたサイト
Railsマイグレーションのindex、foreign_keyの設定
Railsで外部キー制約のついたカラムを作る時のmigrationの書き方
Rails4 外部キーをテーブルに設定するための、3通りのマイグレーションの書き方。
Railsマイグレーションの外部キー制約を表現するreferencesについて
Railsで別名の外部キーを設定する方法