YASD-TECH
YASD TECH
# Rails

enum の値を範囲で絞る(statuses と終端なし Range)

投稿日:2026/7/28

更新日:2026/7/28

ttitleImage

enum の値を範囲で絞る(statuses と終端なし Range)

where(status: statuses[:preparing]..) のような書き方は、3つの記法が合体している。

ruby
class Order < ApplicationRecord
  enum :status, { draft: 0, cart: 10, preparing: 50, shipped: 60, delivered: 70 }
end

Order.where(status: Order.statuses[:preparing]..)
# => status >= 50 の注文(= preparing 以降のステータス全部)

statuses — enum が生成するマッピング Hash

enum を定義すると、複数形のクラスメソッドが自動で生えて、定義したマッピングをそのまま返す。

ruby
Order.statuses
# => {"draft"=>0, "cart"=>10, "preparing"=>50, "shipped"=>60, "delivered"=>70}

Order.statuses[:preparing]   # => 50
Order.statuses["preparing"]  # => 50

ActiveSupport::HashWithIndifferentAccess なので、キーはシンボルでも文字列でも引ける。

役割は「50 という生の数字をコードに書かずに、名前から引く」こと。DB に入っているのは整数なので、比較には整数が必要になる。statuses[:preparing] を挟むことで、マッピングを変えたときにクエリ側を直さなくて済む。

50.. — 終端を省略した Range

Ruby 2.6+ の endless range。50..Float::INFINITY のようなもの。

ruby
(50..).include?(60)  # => true
(50..).end           # => nil

先頭を省略した ..50(beginless range, Ruby 2.7+)もある。

where に Range を渡すと比較演算になる

ActiveRecord は Range を SQL の比較に変換する。終端がなければ >= だけになる。

ruby
where(status: 50..)     # status >= 50
where(status: ..50)     # status <= 50
where(status: 10..50)   # status BETWEEN 10 AND 50
where(status: 10...50)  # status >= 10 AND status < 50

.....(終端を含むかどうか)の違いはそのまま SQL に出るので、境界値を扱うときは注意。


注意点

Range の端点にシンボルは書けない

ruby
Order.where(status: :preparing)     # ⭕ enum が 50 に変換してくれる
Order.where(status: :preparing..)   # ❌ ArgumentError(bad value for range)

単体の値なら enum のキャストが効くが、Range の中までは面倒を見てくれない。だから statuses[:preparing].. と書いて整数に落とす必要がある。

「以降」は数値順に意味があることが前提

範囲で絞るということは、enum の数値順が業務上の進行順と一致していることを暗黙の前提にしている。

ruby
enum :status, { draft: 0, cart: 10, preparing: 50, shipped: 60, delivered: 70 }
#                                   ~~~~~~~~~~~~ ここ以降が「進行済み」

10 刻みにしてあるのは、後からステータスを挟めるようにするため。preparing の前に新ステータスを足したいときは 40、間に足したいときは 55 のように空き番号を使う。ここで既存の番号を振り直すと、status >= 50 という条件の意味が変わってしまう(そして DB の既存レコードも全件更新が必要になる)。

数値を直書きしない

ruby
where(status: 50..)                    # ❌ 50 が何か読めない
where(status: statuses[:preparing]..)  # ⭕ 「preparing 以降」と読める

生成される SQL は同じだが、後者は「なぜこの境界なのか」が名前で残る。


関連

  • scope で検索条件に名前をつける — この条件を scope に切り出して名前をつける話

Index

  • enum の値を範囲で絞る(statuses と終端なし Range)
  • ① statuses — enum が生成するマッピング Hash
  • ② 50.. — 終端を省略した Range
  • ③ where に Range を渡すと比較演算になる
  • 注意点
  • Range の端点にシンボルは書けない
  • 「以降」は数値順に意味があることが前提
  • 数値を直書きしない
  • 関連