🐰

ActiveRecord で integer 型カラムの数値範囲に制限をかける

2024/03/06に公開

Rails の ActiveRecord で、数値型のカラムに対して数値範囲の制限をかける方法について備忘録としてまとめます。

結論

  • migration ファイルで指定する limit は大きさではなくバイト数
  • Model 側で numericality validates を設定したほうがよさげ
  • 有効/無効 のような数種類のフラグや選択式の値を管理するなら、enum の方がわかりやすい

やりたかったこと

モデル名やカラム名は架空のものですが、以下のように、integer 型のカラム(:age, :account_status)に入る数値に以下のような数値範囲の制限をかけたかったのです。

カラム 制限
age 0 ~ 19 まで登録可能
account_status 0 なら無効、1 なら有効
class CreateChirdren < ActiveRecord::Migration[7.1]
  def up
    create_table :chirdren do |t|
      t.string :email, :null => false, comment: "メールアドレス"
      t.string :name, :null => false, comment: "名前"
      t.integer :age, default: 0, comment: "年齢"
      t.integer :account_status, comment: "アカウント有効性(0: 無効, 1: 有効)"
      t.timestamps
    end
  end

  def down
    drop_table :children
  end
end

migration ファイルで指定する limit は大きさではなくバイト数

当初、下記のように migration ファイルで、limit で最大の数を指定しようとしていました。

  t.integer :age, default: 0, limit: 19, comment: "年齢"

これは間違いで、この場合、age カラムは 19 バイトの制限をかけようとしているということになります。

https://railsguides.jp/active_record_migrations.html#カラム修飾子

Model 側で numericality validates を設定したほうがよさげ

なので、migration ファイルではなく、Model 側で制限をかけます。
numericality ヘルパーに、数値範囲オプションで制約をかけることができます。

class Children < ApplicationRecord
  validates :age, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 19 }
end

上記の例では、以上以下のオプションで設定しましたが、超過未満もそれぞれ、grater_than, less_than のように設定することができます。

また、Rails 7 なら下記のように、in オプションに range オブジェクトを渡してシンプルに記述することもできます。

class Children < ApplicationRecord
  validates :age, numericality: { in: 0..19 }
end

https://railsguides.jp/active_record_validations.html#numericality

有効/無効 のような数種類のフラグや選択式の値を管理するなら、enum の方がわかりやすい

また、有効/無効の2つの値しかとらないデータや、有料/無料プラン(有料でも松竹梅のようにいくつか分かれている場合もありますよね)のような選択式の値を integer 型カラムで管理する場合は、enum で管理する方が個人的にはわかりやすいかなと思います。

class Children < ApplicationRecord
  enum :account_status, { ban: 0, active: 1 }
end

参考

https://railsguides.jp/active_record_migrations.html#カラム修飾子
https://railsguides.jp/active_record_validations.html#numericality

Discussion