search
LoginSignup
8

More than 5 years have passed since last update.

posted at

RailsでenumのカラムをSTIとして使う

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? みたいなメソッドはそのまま使えるので、実は結構有りなのでは・・・!と思ったりしました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
8