Posted at

マイグレーションにおいて参照先テーブル名を自動で推定できないカラムを外部キーとして指定する方法

More than 1 year has passed since last update.


結論

方法は 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


参考文献