208
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

Railsで外部キー制約のついたカラムを作る時のmigrationの書き方

確認した環境は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 になってるからのようです → ここ )

番外編

カラム名に *_id 以外の名前を使いたい

実は t.referencesadd_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

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
208
Help us understand the problem. What are the problem?