0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Rails migration] ユニーク制約を1行で書きたいんだ!

Posted at

概要

テーブル作成時に 「特定のカラムに対して、ユニーク制約を適用したい」 ケースがよくあると思います。

ユニーク制約を適用する方法として、2パターンがあるのですが、個人的に「1」の書き方が好みではないので、スッキリ記載できる「2」のパターンをなるべく採用したいと考えています。

  1. create_table 後に add_index を使用する
  2. 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が失敗してくれると嬉しいのですが、、、
この点、何かしたらの理由がある場合はコメントで教えてくれると嬉しいです🙋‍♂️

良いエンジニアライフを!

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?