LoginSignup
785

Railsの外部キー制約とreference型について

Last updated at Posted at 2017-11-24

株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。

Railsで外部キーのカラムを追加する際に、reference型を使うことがあると思います。
reference型の使い方に関しては以下のように様々な記事があります。

外部キーをreferences型カラムで保存する
Rails4 外部キーをテーブルに設定するための、3通りのマイグレーションの書き方。

しかし、reference型で作成する時はadd_index: true必要なの?foreign_key必要なの?
と混乱してしまうので、備忘録のためにまとめておきます。

前提

アプリケーションとしてはTwitterの簡易版で、登録しているユーザーがツイートができるアプリケーションです。
テーブル構造としては
user : tweet = 1 : N
の関係になっています。
テーブル名はそれぞれ、userstweetsです。

reference型を使わない場合

まずはreference型を使わないで、外部キー制約のついたカラムを作成します。

制約などなにもないカラムの作成

以下のように記述すると、インデックスが貼られない、外部キー制約もつかないカラムを作成することができます。

2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string   :text
      t.integer  :user_id
    end
  end
end

インデックスを貼るカラムの作成

インデックスを貼る場合、2通りの書き方があるようです。
インデックスとはなんぞやという方は こちら をご覧ください。

2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string    :text
      t.integer   :user_id, index: true #indexオプション
    end
  end
end
2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string    :text
      t.integer   :user_id
    end
    add_index :tweets, :user_id
    # add_index :対象のテーブル名, インデックス対象のカラム名
  end
end

外部キー制約が付いているカラムの作成

reference型を使わない場合、foreign_key: trueでは外部キー制約にならないので注意が必要です。
また、外部キー制約をつける場合、インデックスは自動で付与されるので、先ほどのindex: trueは不要になります!(便利ですね)

2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string   :text
      t.integer  :user_id
    end
    add_foreign_key :tweets, :users
    # add_foreign_key :対象のテーブル名, :指定先のテーブル 
  end
end

reference型を使う場合

次に、reference型を使う場合の外部キー制約のついたカラムを作成します。

reference型を使うメリット

reference型を使い、t.reference :userと記述すると2つのメリットがあります。

  • userではなくuser_idというカラム名を作成してくれる
  • インデックスを自動で張ってくれる
2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string    :text
      t.references :user
    end
  end
end

しかし、t.reference :userだけでは外部キー制約はつきません。
ですので、reference型を使う場合は以下のように記述して、外部キー制約をつけることになります。
reference型では外部キー制約をつけるときに、foreign_key: trueが使えるようになります!

2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string     :text
      t.references :user, foreign_key: true
    end
  end
end

ちなみに以下のようにadd_foreign_keyでも大丈夫です。

2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string     :text
      t.references :user
    end
    add_foreign_key :tweets, :users
  end
end

まとめ

外部キー制約のついたカラムを作る際は、以下のように記述するのが手っ取り早いです。

2017_create_tweets.rb
class CreateTweets < ActiveRecord::Migration[5.0]
  def change
    create_table :tweets do |t|
      t.string     :text
      t.references :user, foreign_key: true
    end
  end
end

ちなみにadd_columnの場合は以下の形が手っ取り早いです。

2017_add_column.rb
class AddColumn < ActiveRecord::Migration[5.0]
  def change
    add_reference :tweets, :user, foreign_key: true
  end
end

追記

紐付き先のテーブル名とカラム名に別名にしたい場合は以下のようになります。

class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :teams do |t|
      t.bigint :owner_id, index: true
    end

    add_foreign_key :tweets, :users, column: :owner_id
  end
end
class AddColumnToUsers < ActiveRecord::Migration[5.0]
  def change
    add_reference :tweets, :owner, foreign_key: { to_table: :users }
  end
end

参考にしたサイト

Railsマイグレーションのindex、foreign_keyの設定
Railsで外部キー制約のついたカラムを作る時のmigrationの書き方
Rails4 外部キーをテーブルに設定するための、3通りのマイグレーションの書き方。
Railsマイグレーションの外部キー制約を表現するreferencesについて
Railsで別名の外部キーを設定する方法

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
785