Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails 6.1: CHECK制約のサポートをマイグレーションに追加(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

なお、該当のAPIドキュメントは以下です。

Rails 6.1: CHECK制約のサポートをマイグレーションに追加(翻訳)

従来のRailsでは、ADD CONSTRAINT カラム名 CHECK 制約を行うにはマイグレーションで生SQLを実行しなければなりませんでした。

Bookモデル用のテーブルを作成し、そのpriceフィールドに「価格は100より大きいこと」という制約を付けたいとします。従来は以下のように、テーブル作成後にマイグレーションで生SQLを書くしか方法がありませんでした。

class CreateBooks < ActiveRecord::Migration
  def change
    create_table :books do |t|
      t.string :name
      t.integer :price
    end
  end
end
class AddConstraintToBooks < ActiveRecord::Migration
  def up
    execute "ALTER TABLE books ADD CONSTRAINT price_check CHECK (price > 100)"
  end

  def down
    execute "ALTER TABLE books DROP CONSTRAINT price_check"
  end
end

しかもこのマイグレーションはそのままではロールバックできないので、upメソッドとdownメソッドを別々に書かなければいけません。

解決方法check_constraint:add_check_constraintremove_check_constraint

Rails 6.1のマイグレーションにcheck_constraintメソッドが追加され、テーブル作成時にDSLとしてcheck_constraintを使うことも、テーブル作成後のマイグレーションで使うこともできるようになりました(#31323)。

テーブル作成時にcheck_constraintを使う場合の構文は以下のとおりです。

create_table :table_name do |t|
  ...
  t.check_constraint [constraint_name], [constraint]
end

既存のテーブルで制約を追加または削除するには、check_constraintを以下の構文で用います。

add_check_constraint :table_name, :constraint_condition, name: "constraint_name"
remove_check_constraint :table_name, name: "constraint_name"

add_check_constraintメソッドとremove_check_constraintメソッドは、どちらもロールバック可能である点にご注目ください。

例:

先ほどのBookモデルの例を用います。

以下のマイグレーションでは、booksテーブル自身を作成するときにcheck_constraintメソッドを追加していることにご注目ください。

class CreateBooks < ActiveRecord::Migration
  def change
    create_table :books do |t|
      t.string :name
      t.integer :price
      t.check_constraint "price_check", "price > 100"
    end
  end
end

別のマイグレーションで、booksテーブルにprice_check制約を追加する場合は以下のように書きます。

class CreateBooks < ActiveRecord::Migration
  def change
    add_check_constraint :books, "price > 100", name: "price_check"
  end
end

別のマイグレーションで、price_check制約をbooksテーブルから削除するには以下のように書きます。

class CreateBooks < ActiveRecord::Migration
  def change
    remove_check_constraint :books, name: "price_check"
  end
end

関連記事

Rails 6.1: 属性にデフォルト値を設定しても型が失われなくなった(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。