背景
Rails 4.1 より ActiveRecord::Enum
が利用可能となりました。
これにより以下の様な記述が可能となります。
class User < ActiveRecord::Base
enum role: [:general, :admin]
...
end
# role が admin なユーザを取得する
user = User.admin.first!
# admin かどうか
user.admin?
# role を確認
user.role # => "general"
# role を admin に変更
user.admin!
# role の取りうる値を確認
User.roles # => {"general"=>0, "admin"=>1}
これまで区分値として保持していた値が簡単に管理できるようになってハッピーです。
注意点
とっても便利な Active::Enum ですがいくつか注意点があります
- 要素を追加する場合は末尾にアペンドすること
ActiveRecord::Enum により定義された値は、内部的には 0, 1, 2, 3... という数値型に変換されます。新しく要素を追加する場合には末尾にアペンドするようにしましょう。
変更前
status
に 新しく :in_review
を追加したい
class Article < ActiveRecord::Base
# => 0-:new, 1-:approved, 2-:rejected 3-:in_review
enum status: [:new, :approved, :rejected]
...
end
悪い例
配列の途中に新しい要素を追加すると、以降のマッピングが変わってしまい、既存データとの整合性が取れなくなってしまいます。
class Article < ActiveRecord::Base
# 既存データとの整合性が取れなくなってしまう!!
# => 0-:new, 1-:approved, 2-:in_review, 3-:rejected 4-:in_review
enum status: [:new, :in_review, :approved, :rejected]
...
end
良い例
新しく要素を追加するときは配列の末尾にすることで、既存データとの整合性が取れます。
class Article < ActiveRecord::Base
# => 0-:new, 1-:approved, 2-:rejected, 3-:in_review, 4-:in_review
enum status: [:new, :approved, :rejected, :in_review]
...
end
- 同じ名前を同じクラス内で利用しないこと
複数の enum フィールドに同じ名前を使わないようにしましょう。
class Article < ActiveRecord::Base
enum status: [:new, :approved, :rejected]
enum category: [:lifehack, :biz, :animals, :new] # :new が重複!
...
end
- scope で利用する場合には数値を利用すること
scope 内にて検索条件として利用する場合にはシンボルではなく数値を利用しましょう。
class Article < ActiveRecord::Base
enum status: [:new, :approved, :rejected]
scope :hidden, -> { where('status <> ? AND status <> ?', STATUS[:new], STATUS[:rejected]) }
end
(番外)ユーザ向けの入出力項目としては利用しないこと
現在のところ ActiveRecord::Enum は内部処理のみで利用し、form での入力項目や画面での出力項目として利用することは意図していないようです。
参考: Rails4 - ActiveRecord::Enum の使いドコロ - Qiita
回避方法はいくつかありますが、頭の片隅においておくとよいかと思います。