確認した環境はRails5.1.3です。
テーブル作成時
外部キー制約をかけるカラム名により、多少書き方が異なります。
カラム名が #{参照先テーブル名の単数形}_id
(e.g. 参照先がusers.id なら user_id)の場合が基本形で、参照先テーブル指定が省略できます。
それ以外の場合は、参照先テーブルが推測不可能なので、 オプションで指定する必要があります。
class CreateTasks < ActiveRecord::Migration[5.1]
def change
create_table :tasks do |t|
t.string :name, null: false
# 基本形: user_idという名前で users.id への外部キー制約をはる
t.references :user, foreign_key: true
# 応用形: user_id以外の名前(assignee_id)という名前で users.id への外部キー制約をはる
t.references :assignee, foreign_key: { to_table: :users }
t.timestamps
end
end
end
カラム追加時
既存テーブルにカラムを追加する時の書き方です。
class AddUserIdToTasks < ActiveRecord::Migration[5.1]
def change
# 基本形: user_idという名前で users.id への外部キー制約をはる
add_reference :tasks, :user, foreign_key: true
# 応用形: user_id以外の名前(assignee_id)という名前で users.id への外部キー制約をはる
add_reference :applicants, :assignee, foreign_key: { to_table: :users }
end
end
注意事項
-
foreign_key
オプションを省略してしまうと、外部キー制約がはられません。忘れないようにしましょう。
豆知識
-
create_table
内でのt.references
やadd_reference
を使うとdefaultでindexが作られます- indexを作りたくない場合はオプションで明示的に
index: false
しましょう - (
ActiveRecord::ConnectionAdapters::ReferenceDefinition#initialize
の default値でindex: true
になってるからのようです →
ここ )
- indexを作りたくない場合はオプションで明示的に
番外編
カラム名に *_id
以外の名前を使いたい
実は t.references
や add_reference
を使った時には、カラム名の後ろに自動で _id
が付与され、外せません。
( ActiveRecord::ConnectionAdapters::ReferenceDefinition#column_name
で、固定的に _id
という suffix を付与しています → ここ )
そのような場合は、今のところ、外部キー制約のないカラムを追加した後に add_foreign_key
で別途外部キー制約を追加する方式をとらざるを得ないようです。
# テーブル作成時に、 assigned_to カラムを作り、外部キー制約をはる
class CreateTasks < ActiveRecord::Migration[5.1]
def change
create_table :tasks do |t|
t.string :name, null: false
t.bigint :assigned_to, index: true
t.timestamps
end
add_foreign_key :tasks, :users, column: :assigned_to
end
end
# 既存テーブルに assigned_to カラムを追加し、外部キー制約をはる
class AddAssignedToToTasks < ActiveRecord::Migration[5.1]
def change
# assigned_to カラムを追加
add_column :tasks, :assigned_to, :bigint, index: true
# 別途外部キー制約を追加
add_foreign_key :tasks, :users, column: :assigned_to
end
end