Help us understand the problem. What is going on with this article?

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

More than 3 years have 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

参考文献

pepabo
「いるだけで成長できる環境」を標榜し、エンジニアが楽しく開発できるWebサービス企業を目指しています。
https://pepabo.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした