ActiveSupport::StringInquirer を使って、ステータスを active? みたいに管理する

More than 1 year has passed since last update.


はじめに

Rails で User モデルに status というカラムがあるとき、

Rails.env.production?

のように

user.status.active?

と書きたいときがあります。その書き方の例です。


シンプルな実装

ActiveSupport::StringInquirer もしくは、String#inquiry メソッドを使うと簡単に実装できます。

Userモデルには string 型の status というカラムがあるものとします

app/mode/user.rb

class User < ApplicationRecord

def status
attribute(:status).inquiry
end
end

[1] pry(main)> user = User.new

=> #<User:0x3ff520751674>
[2] pry(main)> user.status = :active
=> :active
[3] pry(main)> user.status.active?
=> true
[4] pry(main)> user.status = :inactive
=> :inactive
[5] pry(main)> user.status.active?
=> false
[6] pry(main)> user.status.inactive?
=> true

簡単ですね。


ちょっと凝った実装

1個のモデルの1個の属性だけにこれを適用するならば良いのですが、数が増えてくると同じようなことを何度も書く必要が出て来ます。

そんなときは、クラスマクロを実装して、シンプルに済ませませましょう。

app/mode/application_record.rb

class ApplicationRecord < ActiveRecord::Base

self.abstract_class = true
class << self
def inquiry *attrs
attrs.each do |attr|
define_method attr.intern do
attribute(attr).inquiry
end
end
end
end
end

app/mode/user.rb

class User < ApplicationRecord

inquiry :status
end

試してみましょう。

[1] pry(main)> user = User.new

=> #<User:0x3fcca0cb0c58>
[2] pry(main)> user.status = :active
=> :active
[3] pry(main)> user.status.active?
=> true
[4] pry(main)> user.status = :inactive
=> :inactive
[5] pry(main)> user.status.active?
=> false
[6] pry(main)> user.status.inactive?
=> true

同じように動きますね。引数は複数取るようにしたので、

class User < ApplicationRecord

inquiry :status, :gender
end

のように書くと

user.gender.female?

=> true

のようなメソッドも使えるようになります。


参考

ActiveSupport::StringInquirer

http://api.rubyonrails.org/classes/ActiveSupport/StringInquirer.html