概要
テーブル作成時に 「特定のカラムに対して、ユニーク制約を適用したい」 ケースがよくあると思います。
ユニーク制約を適用する方法として、2パターンがあるのですが、個人的に「1
」の書き方が好みではないので、スッキリ記載できる「2
」のパターンをなるべく採用したいと考えています。
-
create_table
後にadd_index
を使用する -
unique: true
を使用する
ただいざ作業する際に 「あれ?どうするんだっけ?」 と混乱することが多かったので、記事化しました。
結論
以下のようにします。
create_table :users do |t|
t.string :unique_code, index: { unique: true }
end
ダメなケース(落とし穴)
以下の書き方では、マイグレショーンは成功 するが、ユニーク制約は適用されません!
なんだって!?
create_table :users do |t|
t.string :unique_code, unique: true
end
検証
検証していきましょう!
検証のため、事前にスキーマ情報をモデルに追加してくれる 「annotate gem
」をインストールしておくと便利です。
正常形
モデルと、マイグレーションを作成します。
rails g model Test unique_code:string
invoke active_record
create db/migrate/20250220105451_create_tests.rb
create app/models/test.rb
invoke rspec
create spec/models/test_spec.rb
invoke factory_bot
create spec/factories/tests.rb
マイグレーションファイルを変更します。
class CreateTests < ActiveRecord::Migration[7.0]
def change
create_table :tests do |t|
# , index: { unique: true } を追加
t.string :unique_code, index: { unique: true }
t.timestamps
end
end
end
実行します。
rails db:migrate
モデルの内容を見ると、ユニーク制約が適用されていることがわかりますね!
OK!
# == Schema Information
#
# Table name: tests
#
# id :bigint not null, primary key
# unique_code :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_tests_on_unique_code (unique_code) UNIQUE
#
class Test < ApplicationRecord
end
異常系
さて次は、期待した挙動にならないパターンを見ていきましょう。
rails g model AbnormalTest unique_code:string
invoke active_record
create db/migrate/20250220105951_create_abnormal_tests.rb
create app/models/abnormal_test.rb
invoke rspec
create spec/models/abnormal_test_spec.rb
invoke factory_bot
create spec/factories/abnormal_tests.rb
マイグレーションファイルを変更します。
class CreateAbnormalTests < ActiveRecord::Migration[7.0]
def change
create_table :abnormal_tests do |t|
# , unique: true を追加
t.string :unique_code, unique: true
t.timestamps
end
end
end
実行します。
rails db:migrate
マイグレーションは成功します(個人的にはエラーになってほしい...🥲)
そして、ユニーク制約が適用されていないことがわかりますね...
# == Schema Information
#
# Table name: abnormal_tests
#
# id :bigint not null, primary key
# unique_code :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class AbnormalTest < ApplicationRecord
end
まとめ
本来はMigrationが失敗してくれると嬉しいのですが、、、
この点、何かしたらの理由がある場合はコメントで教えてくれると嬉しいです🙋♂️
良いエンジニアライフを!