はじめに
この記事の概要
こんにちは、Rubyをメインで書いている株式会社TOKOSのツキヤです!
今回は、マイグレーションファイル内で外部キー制約やインデックスの設定をする方法を説明します!
ツキヤ
外部キー制約とは、外部キーに対して親テーブルのIDとして存在するものしか指定できないようにする制約のことです。
userテーブルとtweetテーブルが1対多の関係だとすると、下記画像のような関係になります!
外部キー制約を指定することで、データの整合性をより正確にすることができます😎
かなり簡単に説明すると、カラムに指定すると、データを取得する時に早くなるものです!
また、ユニーク(一意)制約をかけることも可能です!
ここで詳しく説明するとかなり長くなってしまうので、詳しく調べたい方はググって見てください🙇♂️
対象読者
- マイグレーションファイルに外部キー制約を指定したい方
- マイグレーションファイルにインデックス・ユニーク制約を指定したい方
外部キー系
references
よく使用されるreferencesには、下記のようにforeign_key: trueを入れるだけで完了です!
class CreateTweets < ActiveRecord::Migration[7.0]
def change
create_table :tweets do |t|
t.references :user, null: false, foreign_key: true
t.string :body, null: false
t.timestamps
end
end
end
今まで入れてなかった人は、とりあえず書いておいた方が無難です!
ツキヤ
また、外部キー制約を詳細にカスタマイズすることもできます!
class CreateTweets < ActiveRecord::Migration[7.0]
def change
create_table :tweets do |t|
t.references :user, null: false, foreign_key: { on_update: :cascade, on_delete: :cascade }
t.string :body, null: false
t.timestamps
end
end
end
on_updateは、親のID(この場合はuser.id)が変更された場合にどうするかの挙動を決めています。
:cascadeは、親の変更に合わせるという意味です!
on_deleteも同様に、親のIDが削除された際の挙動の設定です!
ここまで設定をしておくと、更にデータの整合性がとれそうですね😎
後から設定する場合
テーブル作成の際に忘れてしまった場合や、後で制約を変更したい場合は下記のように記述すればOKです!
class AddForeignKeyTweets < ActiveRecord::Migration[7.0]
def change
add_foreign_key :tweets, :users, column: :user_id, on_update: :cascade, on_delete: :cascade
end
end
逆に削除したい場合は下記のような記述です!
class RemoveIndexTweets < ActiveRecord::Migration[7.0]
def change
remove_foreign_key :tweets, :users, column: :user_id
end
end
ツキヤ
インデックス系
基本形
インデックスに関しては、つけたいカラムに対してindex: trueと記述するだけです!
class CreateTweets < ActiveRecord::Migration[7.0]
def change
create_table :tweets do |t|
t.references :user, null: false, foreign_key: true
t.string :body, null: false, index: true
t.timestamps
end
end
end
referencesの場合は、自動でインデックスが付いているので特になにもしなくてOKです!
ユニーク制約
ここからはユニーク制約です!
テーブル設計の際に、has_one(1対1)の実装をする時があると思います。
この際に同じ親IDをもつレコードは要らないのでユニーク制約を下記のようにかけます!
class CreateUserInformations < ActiveRecord::Migration[7.0]
def change
create_table :user_informations do |t|
t.references :user, null: false, foreign_key: true, index: { unique: true }
t.string :body, null: false
t.timestamps
end
end
end
index: { unique: true }の部分ですね!
こうするだけでユニーク制約がかかります!
複合ユニーク制約
お次は複数のカラムに対するユニーク制約です!
例えば、お気に入り機能を実装する際に「同じユーザーが1つの投稿に2回以上お気に入りをさせない」場合に必要かと思います!
class CreateFavorites < ActiveRecord::Migration[7.0]
def change
create_table :favoritess do |t|
t.references :user, null: false, foreign_key: true
t.references :tweet, null: false, foreign_key: true
t.timestamps
end
add_index :favorites, [:user_id, :tweet_id], unique: true
end
end
9行目のような記述をすることで、複合ユニーク制約の実装ができます!
2つのカラムにまたがる設定のため、別途設定のための文書を記述してあげる必要があります!
後から設定する場合
こちらも外部キー制約と同じく下記の様な形になります!
削除もまとめて書いちゃいます!
class AddIndexTweets < ActiveRecord::Migration[7.0]
def up
add_index :favorites, [:user_id, :tweet_id], unique: true
end
def down
remove_index :favorites, [:user_id, :tweet_id], unique: true
end
end
終わりに
今回はモデルファイルでは無く、DB側での制約を紹介しました!
ユニーク制約の場合、アプリケーション側(モデルファイル)で同様のバリデーションをかけないとエラーになってしまいますので注意してください(ex: validates: column_name, uniquness: true)
アプリケーション側でちゃんとvalidationをかけることも大事ですが、DB側でも今回のような制約を加えることでより堅牢なサービスを目指しましょう😆
Railsの勉強をしたい方はこの本が参考になるかと思いますので興味がある方は是非読んで見て下さい🙇♂️