Reputation: 2666
I am new to rails and am working on one of my first rails projects, it is an invoice app with nested line items within the invoice form. I want to calculate the total invoice before I save the invoice. I get it to save nicely if just added items during the save process, but it doesn't calulate the total correctly if one of the nested line items is tagged to be deleted. I would have to go back in and save again to get the correct total billed amount.
class Invoice < ActiveRecord::Base
attr_accessible :job_name, :items_attributes, :tax1, :tax2, :subtotal
before_save :calculate_totals
has_many :items, :dependent => :destroy
accepts_nested_attributes_for :items, allow_destroy: true
private
def calculate_totals
self.subtotal = 0
self.items.each do |i|
self.subtotal = self.subtotal + (i.quantity * i.cost_per)
end
end
end
I'm note sure how this differs from params but the problem item record is listed in the requested paramaters with :_destroy = true
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"+OqRa7vRa1CKPMCdBrjhvU6jzMH1zQ=",
"invoice"=>{"client_id"=>"1",
"job_name"=>"dsdsadsad",
"items_attributes"=>{"0"=>{"name"=>"jhksadhshdkjhkjdh",
"quantity"=>"1",
"cost_per"=>"50.0",
"id"=>"21",
"_destroy"=>"false"},
"1"=>{"name"=>"delete this one",
"quantity"=>"1",
"cost_per"=>"10.0",
"id"=>"24",
"_destroy"=>"true"}}},
"commit"=>"Update Invoice",
"id"=>"8"}
Thanks for you help.
Upvotes: 2
Views: 871
Reputation: 2666
I found a solution that seems to work:
class Invoice < ActiveRecord::Base
attr_accessible :job_name, :items_attributes, :tax1, :tax2, :subtotal
before_save :calculate_totals
has_many :items, :dependent => :destroy
accepts_nested_attributes_for :items, allow_destroy: true
private
def calculate_totals
self.subtotal = 0
self.items.each do |i|
unless i.marked_for_destruction?
self.subtotal += (i.quantity * i.cost_per)
end
end
end
The key is the method marked_for_destruction? In this case I was checking for items that weren't marked for destroy. Here's the link to the rails api that explains it: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Thanks Steve
Upvotes: 2
Reputation: 8604
You have calculated items before Invoice
was saved, so it calculated items destroyed too, as in API document has guide:
Note that the model will not be destroyed until the parent is saved.
So you just need change before_save
to after_save
, it will works.
Upvotes: 0
Reputation: 452
params[:invoice][:items_attributes].each do |i|
self.subtotal = self.subtotal + (i[:quantity].to_f * i[:cost_per].to_f) unless i['_destroy'] == 'true'
end
Upvotes: 0