enum
の中身で処理が別れるようなコード
enum
を使っていると以下のようなコードが増えていくことがある。
明らかに enum
の値によって振舞いを変えているので、 enum
の値によってそもそもクラスを変えていきたい。 というわけでenumで使っているカラムをSTIとしても使えないのか試してみました。
class Payment < ActiveRecord::Base
enum means: { credit_card: 0, bank_transfer: 10, paypal: 20 }
def complete!
if credit_card?
# do something
elsif bank_transfer?
# do something
end
end
def cancel!
if credit_card?
# do something
elsif bank_transfer?
# do something
end
end
end
enum
のカラムをSTIでも使う
結論、以下のように書けばいけるっぽい。
class Payment < ActiveRecord::Base
enum type: { credit_card: 0, bank_transfer: 10, paypal: 20 }
class << self
def find_sti_class(type)
type_name = types.key(type.to_i) # enumのhashから該当するkeyを取得する
"Payment::#{type_name.to_s.camelize}".constantize
end
def sti_name
types[name.demodulize.underscore]
end
end
def complete!
fail NotImplementedError
end
def cancel!
fail NotImplementedError
end
end
こうしておけば、 通常のSTIと同じく、 各 type
に対応するクラスを定義できる。
class Payment::CreditCard < Payment
def complete!
end
def cancel!
end
end
class Payment::BankTransfer < Payment
def complete!
end
def cancel!
end
end
class Payment::PayPal < Payment
def complete!
end
def cancel!
end
end
最初から enum
で処理を変える必要があることがわかっているのであれば、素直にテーブルを分けたり普通のSTIを選択した方がハマりどころも少なそうで良いとは思います。
が、これはこれでDBにクラス名がそのまま入ることもないし、enum
で生成されるスコープや credit_card?
みたいなメソッドはそのまま使えるので、実は結構有りなのでは・・・!と思ったりしました。