LoginSignup
11
9

More than 5 years have passed since last update.

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

Posted at

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

11
9
1

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
  3. You can use dark theme
What you can do with signing up
11
9