Search code examples
ruby-on-railsrubyinheritanceruby-on-rails-4sti

Rails 4 STI inheritance


I'm using single table inheritance successfully like so:

class Transaction < ActiveRecord::Base
    belongs_to :order
end

class Purchase < Transaction
end

class Refund < Transaction
end

The abbreviated/simplified PurchaseController looks like this:

class PurchaseController < TransactionController
  def new
    @transaction = @order.purchases.new(type: type)
  end

  def create
    @transaction = @order.purchases.new secure_params
    if @transaction.save
      redirect_to @order
    else
      render :new
    end
  end
end

The abbreviated/simplified Purchase model looks like this:

class Purchase < Transaction
  attr_accessor :cc_number, :cc_expiry, :cc_csv
end

What I'm trying to do is have different variations of a purchase, for instance a cash purchase & a cheque purchase. The issue is I'm not sure how to call the model for that variation.

For example:

class Cash < Purchase
  attr_accessor :receipt_no
end

class CashController < TransactionController
  def new
    # This will use the Purchase.rb model so that's no good because I need the Cash.rb model attributes
    @transaction = @order.purchases.new(type: type)

    # This gives me the following error:
    # ActiveRecord::SubclassNotFound: Invalid single-table inheritance type: Purchase is not a subclass of Cash
    @transaction = Cash.new(type: 'Purchase', order: @order.id)
  end
end

Solution

  • I'm not sure why it doesn't work for you, this works fine for me:

    @order.purchases.new(type: "Cash") # returns a new Cash instance
    

    You can also push a new Cash on to the association if you are ready to save it:

    @order.purchases << Cash.new
    

    Or you can define a separate association in Order:

    class Order < ActiveRecord::Base
      has_many :cashes
    end
    
    @order.cashes.new # returns a new Cash instance