Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby on Rails - before_save calculation on accepts_nested_attributes_for

I have an invoice model, that "has many" invoice items. I have a form that allows you to create/edit an invoice, and this form accepts nested attributes for the invoice items.

In my invoice model, there is a "total_amount" field that is a calculated field (the sum of "amount" from the invoice items).

I want to calculate this amount when an invoice is created, or updated. I am trying to do this in the before_save event of my invoice model. The code below almost works, however the total that gets saved is always one step behind. I.e. if I have an invoice with a total of $20, and I edit this invoice and change the invoice items to total $15, then save my invoice, the total doesn't change. If I open the same invoice, and then save it again, the total is updated properly.

I assume that my line below that calculates the sum is accessing the line items that are saved in the database already, and not those that have just been changed and are about to be saved. I don't however know how to access those.

class Invoice < ActiveRecord::Base
  has_many :invoice_items, :dependent => :destroy

  accepts_nested_attributes_for :invoice_items, :allow_destroy => true 

  before_save :record_total_amount

  private
    def record_total_amount
      self.total_amount = self.invoice_items.sum('amount')
    end
end

Any help would be much appreciated.

like image 545
Joel Friedlaender Avatar asked Feb 28 '11 06:02

Joel Friedlaender


2 Answers

I solved this problem, I had to replace the calculation line with this one:

self.total_amount = invoice_items.map(&:amount).sum
like image 70
Joel Friedlaender Avatar answered Oct 24 '22 09:10

Joel Friedlaender


Try this:

self.total_amount = invoice_items.reject(&:marked_for_destruction?).map(&:amount).sum

like image 31
hyeomans Avatar answered Oct 24 '22 08:10

hyeomans