カクカクしかじか

技術的なアレコレ

RailsでActiveRecord::Enumを使わずにそれっぽい機能を実装する方法

経緯

普段の業務でmongoidというActiveRecordとは異なるORM(正確にはODM)を使っています。
当たり前ですが、ActiveRecordを使用しないRailsアプリではActiveRecordの使用を前提としたRailsの機能を使用することが出来ません。
というわけで、ActiveRecord::Enumが使えないけど、同じ機能を自前で実装する方法をメモ。

前提

例えば status というString型のデータを入れるカラムを持つモデルに対して各ステータスかどうかをチェックするための cancel? などの真偽値を返すメソッドを生やそうという場合を想定してます。

結論:define_methodを使う

hoge.rb

class Hoge
  include Mongoid::Document
  include Mongoid::Timestamps
    
  field :status, type: String
  STATUS_LIST = ["cancel", "pending", "complete"].freeze

  # ステータスを判別するメソッドを定義
  # #{_status}? メソッドが追加される
  STATUS_LIST.each { |_status| define_method("#{_status}?".to_sym, -> { status == _status }) }
end

define_methodの構文的にはこんな感じ!

define_method(:foo, lambda{ puts "foo" })

foo #=> "foo"

コレによってモデルのインスタンスで定義したメソッドが使用可能になります!

hoge = Hoge.new
hoge.cancel?
=> false

最後に

メタプロはRubyの醍醐味だと思うので実践でも使っていきたい!!!
(メタプロで書く必要ないのにメタプロ 乱用しないように気を付けながらw)