ひよっこエンジニアの雑多な日記

なんとかWeb系のエンジニアをやっています。

【Rails】enumで特定の値を選択肢から省きたい

きむらです。またもやenum関連ですがちょっとなるほどと思ったことがあったので備忘録。

enumに設定している値を全て取り出す

例えばセレクトボックスに選択肢としてenumに設定している値を出す場合などによく使うとおもいます。

# blogというモデルに公開範囲(非公開、公開、一部に公開)のようなステータスがある想定
class Blog < ActiveRecord::Base
  enum status: { unpublish: 0, publish: 1, part_publish: 2 }
end

# enumに設定したstatusの状態をすべて取得する
Blog.statuses
=> {"unpublish"=>0, "publish"=>1, "part_publish"=>2}

てな感じでモデル.enumを設定した属性の複数系と書くことでenumに設定した値を取得することができます!
これを使えばブログの公開範囲選択セレクトボックスを作成するのが簡単になったりします!

enumに設定している特定の値だけを取得したい

便利とはいえ特定の状態だけを選択させたくなるときもあります。
例えば一部に公開(part_publish)を特定の箇所では選択肢に入らないようにしたいとか

そんなときはsliceexceptを使うと幸せになれます!

sliceを使ってpart_publishを省く

Blog.statuses.slice(:unpublish, :publish)
=> {"unpublish"=>0, "publish"=>1}

sliceを用いると引数に指定した値だけを取り出すことができます。
特定の値を省くというより、特定の値だけを取り出すという感じですね!

exceptを使ってpart_publishを省く

Blog.statuses.except(:part_publish)
=> {"unpublish"=>0, "publish"=>1}

exceptを用いると引数に指定した値は取得しないようになります!
省くという意味合いではexceptの方が正しそうですね。

といった感じで簡単にenumに設定した特定の値だけを取得できるようになります!
これらを使ってクラスメソッドなんか作ってあげるとスマートっぽい気がしますね!

class Blog < ActiveRecord::Base
  enum status: { unpublish: 0, publish: 1, part_publish: 2 }

  def self.restrict_statuses
    statuses.except(:part_publish)
  end
end

Blog.restrict_statuses
=> {"unpublish"=>0, "publish"=>1}

slice、exceptは何者か

この二つはActiveSupportのメソッドのようです!
enumを設定して設定内容を取得したもののクラスが以下にになります!

Blog.statuses.class
=> ActiveSupport::HashWithIndifferentAccess

つまりBlog.statusesで取得できるものはハッシュってことになります。
RailsだとハッシュはActiveSupportパイセンの力でちょいちょい強化されていて、その強化された力を用いることで割と簡単にハッシュ操作ができたりします…。sliceexceptはその力の一部であるということです…。

ほんとActiveSupportActiveRecordあたりはよしなにいろんなことをやってくれるので便利すぎるなあという気持ちになります。

最近RailsのよしなにしてくれるところにあぐらかいてRuby力がなくなってきている(そもそもそんなにない)ので、その辺鍛え直さないとなあ…。