【Rails】マイグレーションでカラムに特定の値だけを許可する方法

Railsのマイグレーションファイルで特定のカラムへ格納される値に制約をつけたかったのですが、そのやり方が分からなかったので、備忘録としてまとめます。

バージョン
  • Ruby 3.2.2
  • Rails 7.1.2
  • MySQL8.0
記事の信頼性
  • ぼくは独学で未経験から従業員300名以上の自社開発企業へ転職しました。
  • 実務ではVue.jsとRailsを毎日書いています。
  • 初心者や駆け出しエンジニアがつまづくポイントも身をもってよく理解しています。
目次

問題

勉強の一環でクイズアプリを作っており、QuizChoices(クイズの選択肢)モデルの実装に取りかかっていました。

すべてのクイズは4択形式としたいため、display_orderカラムに1〜4のいずれかの値だけを許可する必要があります。

display_orderカラムに対して、マイグレーションファイルでデータベースレベルでの制約を付けたいのですが、そのやり方がわかりませんでした、、。

解決方法

結論として、以下のようにマイグレーションファイル内でadd_check_constraintメソッドを使うことで実現できました。

class AddConstraintToDisplayOrderOnQuizChoices < ActiveRecord::Migration[7.1]
  def change
    add_check_constraint :quiz_choices, 'display_order BETWEEN 1 AND 4', name: 'display_order_check'
  end
end

rails db:migrateを実行後、db/schema.rbを見てみるとたしかに制約が付与されています↓

  create_table "quiz_choices", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.bigint "quiz_id", null: false
    t.string "content", null: false
    t.boolean "is_correct", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "display_order", default: 0, null: false
    t.index ["quiz_id"], name: "index_quiz_choices_on_quiz_id"
    # 制約が追加されている↓
    t.check_constraint "`display_order` between 1 and 4", name: "display_order_check"
  end

これでカラムに格納される値を限定できました!

捕捉説明

ちなみにadd_check_constraintメソッドは内部的に以下のSQLを生成し、テーブル定義を変更しています。

ALTER TABLE "quiz_choices" ADD CONSTRAINT display_order_check CHECK (display_order BETWEEN 1 AND 4);

またadd_check_constraintメソッドに追加できるオプションは次の2つです。

  1. nameオプション:
    制約に名前をつける。デフォルトだとchk_rails_123abc456defのようになってしまうためつけた方が良い。
  2. validateオプション(PostgreSQLのみ):
    既存のレコードに対して制約を即時適用するか指定する。

おわりに

add_check_constraintメソッドの存在を今回初めて知りました。

参考文献
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

未経験でSESから従業員300名以上の自社開発企業に転職しました。業務や個人開発で直面した問題や、転職・学習の経験を発信していきます。

コメント

コメントする

目次