Reputation: 10207
I have the following models in my Ruby on Rails app :
class Invoice < ActiveRecord::Base
has_many :allocations
has_many :payments, :through => :allocations
end
class Allocation < ActiveRecord::Base
belongs_to :invoice
belongs_to :payment
end
class Payment < ActiveRecord::Base
has_many :allocations, :dependent => :destroy
has_many :invoices, :through => :allocations
end
My problem is that in the Allocation
class I would like to use the total_amount
of all associated invoices, ideally in a before_save
callback.
This isn't possible right now, however, because at the time an allocation
object gets saved it is only associated with one particular invoice
object.
How can this be done with a minimum of database queries?
Upvotes: 1
Views: 186
Reputation: 39695
Invoice.where(asdfasdfasdf).map(&:allocations).flatten.map(&:total_amount).compact.inject(:+)
Because this is rails the database call is nothing. To sum up an array of numbers you can use this:
ary = [0,12,2,6,nil]
ary.compact.inject(:+)
#=> 20
You could clean this up a bit:
class Invoice
#...
def total_amount
allocations.map(&:total_amount).inject(:+) #throws error if there is 1 nil 'total_amount data' value
end
def self.sum_allocation_amounts(sql)
where(sql).map(&:total_amount).inject(:+)
end
end
Its not possible to call self.map(&:allocations)
inside of an Invoice class method without errors so I'm passing in the some basic sql as a workaround. Ideally I'd make it possible to directly call this method on a daisy chain of activerecord where calls for Invoice but that's not working out for me right now ("undefined method map' for Class")
Invoice.sum_allocation_amounts("democol = 'demo params'")
Upvotes: 3