🚀 Railsのenum
、もっと使いやすくしたい
プログラミングをしていると、必ず出会う「状態管理」。
Railsではenum
を使えば簡単に状態管理できますが、標準機能だけでは物足りないと感じたことはありませんか?
- 状態に日本語ラベルを持たせたい
- 状態ごとに説明文も持ちたい
- 将来的に状態の追加・変更に強い設計にしたい
上記を一気に解決するのが、EnumBaseパターンです。
この記事では、普通のenumから一歩踏み込んで、実践で本当に使える状態管理を一緒に目指しましょう!
🛠️ まずは復習:Rails標準のenum
の素晴らしさ
Railsのenum
は、手軽にマジックナンバーを排除できる仕組みです。
class User < ApplicationRecord
enum status: { active: 0, inactive: 1, archived: 2 }
end
user.active!
user.inactive?
User.active
これだけで
- メソッドが生える
- スコープが作れる
- 可読性がグッと上がる(マジックナンバー解消)
最高ですよね。
でも、Rails標準のenum
には一つだけ弱点があります。
状態に付加情報(表示名・説明など)を持たせられない。
これ、地味に辛いんです。
🤔 どんな問題が起こるのか?
例えば、ユーザー状態を日本語で表示したい場合。
標準のenum
ではビュー側でI18n
を使うパターンが多いですが、
管理が煩雑になったり、状態追加時にコードと表示の対応がズレる危険もあります。
<%= t("enums.user.status.#{user.status}") %>
さらに「アクティブユーザーって何?」みたいな説明文も欲しくなると、もうEnumでは対応しきれなくなってしまいます...
🌟 解決策:EnumBaseパターンを使おう!
EnumBaseパターンでは、
「状態」を単なる数字ではなく、情報を持ったオブジェクトとして扱います。
これによって、
ラベル・説明・順番・色指定など
なんでも管理できる、リッチな状態管理が実現できます。
✍️ EnumBaseパターン 実装例
1. 共通親クラスを作成する
class EnumBase
attr_reader :key, :value, :label, :description
def initialize(key, value, label:, description: nil)
@key = key
@value = value
@label = label
@description = description
end
def to_s
label
end
def self.all
constants.map { |c| const_get(c) }
end
def self.find_by_value(value)
all.find { |e| e.value == value }
end
def self.options_for_select
all.map { |e| [e.label, e.value] }
end
end
ここでは
- key:プログラム内での識別子
- value:DBに保存される数値
- label:人間向けの表示名
- description:オプションの説明文
を持たせています。
2. 実際のEnumクラスを作る
class UserStatus < EnumBase
ACTIVE = new(:active, 0, label: 'アクティブ', description: '通常利用中のユーザー')
INACTIVE = new(:inactive, 1, label: '非アクティブ', description: '一時停止中のユーザー')
ARCHIVED = new(:archived, 2, label: 'アーカイブ済み', description: '退会したユーザー')
end
3. モデルとつなぐ
class User < ApplicationRecord
enum status: {
active: UserStatus::ACTIVE.value,
inactive: UserStatus::INACTIVE.value,
archived: UserStatus::ARCHIVED.value
}
def status_label
UserStatus.find_by_value(status_before_type_cast)&.label
end
def status_description
UserStatus.find_by_value(status_before_type_cast)&.description
end
end
✨ リファクタリング事例
もともと、ビューにこんなコードが乱立していたとします。
<% if user.status == 'active' %>
アクティブ
<% elsif user.status == 'inactive' %>
非アクティブ
<% elsif user.status == 'archived' %>
退会済み
<% end %>
これを、EnumBaseパターンを使うと…
<%= user.status_label %>
一行で完結。
しかも状態追加・変更があっても、Enumクラス側だけ直せばOK!
ビューやコントローラーには一切影響を与えません。
🚀 さらに発展:Enumに色やソート順も持たせよう
たとえばEnumBaseをこう拡張すれば、
class EnumBase
attr_reader :key, :value, :label, :description, :color, :sort_order
def initialize(key, value, label:, description: nil, color: nil, sort_order: nil)
@key = key
@value = value
@label = label
@description = description
@color = color
@sort_order = sort_order
end
def self.all_sorted
all.sort_by(&:sort_order)
end
end
色付きバッジ表示や、状態リストの並び替えも自由自在にできちゃいます!
🎯 まとめ
項目 | Rails標準enum | EnumBaseパターン |
---|---|---|
管理できる情報 | 数字とシンボルのみ | ラベル・説明・色・順序・何でも |
拡張性 | 低い | 高い |
ビューコードのシンプルさ | 普通 | 激シンプル |
メンテナンス性 | 普通 | 高い |
📝 最後に
Rails標準のenum
はすばらしい。
でも、それを自分たちの設計思想に合わせて進化させることもまた、Railsらしさだと思います。
状態管理の未来を、あなたの手でリッチにしていきましょう。