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

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

More than 1 year has passed since last update.

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

参考にしたサイト

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

ryouzi
都内で働くWebエンジニアです。Ruby on Rails、インフラなどが得意です。とあるベンチャー企業でチーム開発責任者、サイト運営責任者などやっていました。フットサルと釣りとビールが趣味。
http://ryouzis.hatenablog.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
ユーザーは見つかりませんでした