結論
方法は 2 通りあります。
references
型カラム定義時に :to_table
オプションを使う
references
型のカラム定義時にオプション foreign_key: { to_table: <参照先テーブル名> }
を指定します。
add_foreign_key
の :column
オプションを使う
テーブル/カラム定義後に外部キーとしたいカラムに対して add_foreign_key <テーブル名>, <参照先テーブル名>, column: <カラム名>
を指定します。
問題
テーブル users
, memos
において、memos
の外部キーのカラム名 author
にテーブル users
を参照させるようなマイグレーションを書いたとします。
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name, null: false
t.string :email, null: false
t.string :password_digest, null: false
t.timestamps
end
end
end
class CreateMemos < ActiveRecord::Migration[5.0]
def change
create_table :memos do |t|
t.string :title
t.text :content, null: false
t.references :author, foreign_key: true
t.timestamps
end
end
end
このとき、外部キーのカラム名から参照先テーブルを推定できないため、たとえば PostgerSQL だと次のようなメッセージを出力して、DB のマイグレーションに失敗します。
PG::UndefinedTable: ERROR: relation "authors" does not exist
: CREATE TABLE "memos" ("id" serial primary key, "title" character varying, "content" text NOT NULL, "author_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL, CONSTRAINT "fk_rails_55c841b9ea"
FOREIGN KEY ("author_id")
REFERENCES "authors" ("id")
)
解決方法
解決方法は 2 通りあります。
reference
型カラム定義時に :to_table
オプションを使う
この場合は、references
型カラムを定義している部分でオプション :foreign_key
にサブオプション :to_table
を参照先テーブル名とともに指定することで、正しく参照先テーブルを参照できるようになります。
テーブル定義と一緒にカラムを定義する場合、次のように書きます。
class CreateMemos < ActiveRecord::Migration[5.0]
def change
create_table :memos do |t|
# ...
t.references :author, foreign_key: { to_table: :users }
# ...
end
end
end
カラムだけ定義する場合、次のように書きます。
class AddAuthorToMemos < ActiveReocrd::Migration[5.0]
def change
add_reference :memos, :author, foreign_key: { to_table: :users }
end
end
add_foreign_key
の :column
オプションを使う
この場合は、references
型のカラムだけを定義しておき、別途 add_foreign_key
のオプション :column
で外部キーのカラム名と参照先テーブル名を明示的に関連付けることで、正しく参照先テーブルを参照できるようになります。
テーブル定義と一緒にカラムを定義する場合、次のように書きます。
class CreateMemos < ActiveRecord::Migration[5.0]
def change
create_table :memos do |t|
# ...
t.references :author
# ...
end
end
add_foreign_key :memos, :users, column: :author_id
end
カラム定義後の場合、次のように書きます。
class AddAuthorToMemos < ActiveReocrd::Migration[5.0]
def change
add_reference :memos, :author
end
add_foreign_key :memos, :users, column: :author_id
end