【Rails】外部キー制約が付いているカラムを作成する(reference型について)

Rails で外部キーのカラム(user_idなど)を作成する際、reference型を使うと関連モデルの外部キーを自動生成してくれて便利です。

僕もよくreference型を使うのですが、「外部キー制約」というワードについてはよく理解していないまま今まで何となく使ってきました。(お恥ずかしい限りw)

ということで、今回は「外部キー制約とはどういうもので、何のメリットがあるのか?」についての理解と外部キー制約が付いているカラムを作成する手順を、忘備録も兼ねてまとめてみました。

目次

外部キー制約とは?

外部キーとはテーブル同士の紐付けに用いるカラム(user_id、post_idなどのカラム)のことを言いますが、外部キー制約とは外部キーを登録する際の制限みたいなものです。

外部キー制約を設けた場合、以下のような制限が入ります。

  1. 存在しない値を外部キーとして登録できない
  2. 子テーブルの外部キーに値が登録されている状態で親テーブルのレコードを削除できない

それぞれ詳しくみていきます。

存在しない値を外部キーとして登録できない

例えば、とある投稿サービスでユーザー登録者が10名いたとします。

10名のユーザーID(外部キーはuser_id)はそれぞれ1〜10とします。

この時、user_idカラムに存在しない値(例えば11)を登録しようとするとエラーになります。

子テーブルの外部キーに値が登録されている状態で親テーブルのレコードを削除できない

先ほどの例の続きて、今度は10名のユーザーのうちユーザーID=1のユーザーのみ、何かしらの投稿(post)をしたとします。

ここで、ユーザー10名分のアカウントを削除しようとすると、user_id=1の外部キーを含むレコード(ユーザーアカウント)だけ削除できずにエラーとなります。

つまり、user=1のアカウントを削除するためには、user_id=1を含む子テーブルのレコードを全て削除する必要があります。

ただし、この問題は以下のようにdependent: :destroyのオプションを指定することで解決できます。

class User < ApplicationRecord
  has_many :articles, dependent: :destroy
end

(特定のユーザーアカウントを削除するとuser_idに紐づいた子テーブルのレコードを全て削除してくれる)

reference型を使って外部キーを生成、および外部キー制約を設ける

今回はreference型を使ってarticlesテーブルに外部キーとしてuser_idを作成し、さらに外部キー制約を設けていきます。

reference型を使うメリットは、

  • user_idというカラムを自動生成してくれる
  • user_idのインデックスを自動で貼ってくれる

の2つあります。

ただし、reference型には外部キー制約を自動で設ける機能はありません。

そこで、以下のようにforeign_key: trueオプションを記述することで外部キー制約を設けることができます。

class CreateArticles < ActiveRecord::Migration[7.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :content
      t.references :user, foreign_key: true

      t.timestamps
    end
  end
end

外部キー制約を設けない場合はforeign_key: trueオプションは必要ありません。

rails db:migrateでマイグレーションを実行すると、以下のようにテーブルが作成されます。

  create_table "articles", force: :cascade do |t|
    t.string "title"
    t.text "content"
    t.integer "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_articles_on_admin_id"
  end

user_idが生成されており、user_idのインデックスも振られていることがわかります。

reference型を使わずに外部キー制約を設ける場合

reference型を使わない場合、foreign_key: true オプションでは外部キー制約を設けることができないので注意が必要です。

この場合、以下のように記述します。

class CreateArticles < ActiveRecord::Migration[7.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
      add_foreign_key :articles, :users
    # add_foreign_key :対象のテーブル名, :紐付けしたいテーブル名
  end
end

reference型を使わない場合、indexは自動で貼られないので注意が必要です。

(外部キー制約を設けたいけどindexは貼りたくない場合に有効です)

参考資料

Qiita
Railsの外部キー制約とreference型について - Qiita 株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。Railsで外部キーのカラムを追加する際に、reference型を使うことがあると思います。reference型の使い...
Qiita
外部キーの概要と制約を使うことのメリット・デメリット - Qiita 外部キーとはテーブル同士の紐づけに用いるカラムのこと。users テーブル と user_login_histories テーブル が合った時に、 user_login_histories テー…
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

愛知の34歳。無職で暇になり始めたプログラミング(Ruby on Rails)の忘備録をまとめたブログです。最近は別にやりたいことができたのでプログラミングほぼやっていません。気が向いたらまた再開するかも。僕の日常はメインブログの方で更新しています。

コメント

コメントする

目次