Reputation: 6659
rails 3.2
Invoice.sum(:amount)
Accurately returns the sum of all values in the amount column.
If I do the following:
invoices = Invoice.all
And then:
invoices.sum(:amount)
I get the following error:
NoMethodError: undefined method `+'
Is there a way to do this?
Upvotes: 2
Views: 2532
Reputation: 677
This is because #sum is an ActiveRecord method. What it is essentially doing is building the aggregation into your database query like so (in SQL):
SELECT SUM(name_of_column_to_sum) FROM table_name;
If you want to return the values and store them in a variable (#all),
SELECT * FROM table_name;
and THEN sum them, you are no longer working with an ActiveRecord query, but rather an ActiveRecord relation (an array-like object that is returned from the ActiveRecord query). So, at that point you would need to use vanilla Ruby to sum up. You could use #map and then #sum, but it would be faster and cleaner to just use #inject, like so:
invoices.inject(0){ |sum, invoice| sum + invoice.amount }
Upvotes: 3
Reputation: 2088
If you are certain that there is not a single amount == nil
then what you tried, should work. If you have a single nil column this would result in
NoMethodError: undefined method '+' for nil
. In this case you can either do invoices.map(&:amount).compact.sum
or invoices.sum { |i| i.amount || 0 }
Upvotes: 3
Reputation: 64
You have to use map
function, like this:
invoices.map(&:amount).sum
Upvotes: 1