ActiveRecord::Enum の注意点

  • 38
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

背景

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 ですがいくつか注意点があります

1. 要素を追加する場合は末尾にアペンドすること

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

2. 同じ名前を同じクラス内で利用しないこと

複数の enum フィールドに同じ名前を使わないようにしましょう。

class Article < ActiveRecord::Base
  enum status: [:new, :approved, :rejected] 
  enum category: [:lifehack, :biz, :animals, :new] # :new が重複!
  ...
end

3. 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

回避方法はいくつかありますが、頭の片隅においておくとよいかと思います。