I have a model Channel. The relating table has several column, for example clicks.
So Channel.all.sum(:clicks)
gives me the sum of clicks of all channels.
In my model I have added a new method
def test
123 #this is just an example
end
So now, Channel.first.test
returns 123
What I want to do is something like Channel.all.sum(:test)
which sums the test value of all channels.
The error I get is that test is not a column, which of course it is not, but I hoped to till be able to build this sum.
How could I achieve this?
You could try:
Channel.all.map(&:test).sum
Where clicks is a column of the model's table, use:
Channel.sum(:clicks)
To solve your issue, you can do
Channel.all.sum(&:test)
But it would be better to try achieving it on the database layer, because processing with Ruby might be heavy for memory and efficiency.
If you want to sum by a method which takes arguments:
Channel.all.sum { |channel| channel.test(start_date, end_date) }
What you are talking about here is two very different things:
ActiveRecord::Calculations.sum
sums the values of a column in the database:
SELECT SUM("table_name"."column_name") FROM "column_name"
This is what happens if you call Channel.sum(:column_name)
.
ActiveSupport also extends the Enumerable module with a .sum
method:
module Enumerable
def sum(identity = nil, &block)
if block_given?
map(&block).sum(identity)
else
sum = identity ? inject(identity, :+) : inject(:+)
sum || identity || 0
end
end
end
This loops though all the values in memory and adds them together.
Channel.all.sum(&:test)
Is equivalent to:
Channel.all.inject(0) { |sum, c| sum + c.test }
Using the later can lead to serious performance issues as it pulls all the data out of the database.
Alternatively you do this.
Channel.all.inject(0) {|sum,x| sum + x.test }
You can changed the 0 to whatever value you want the sum to start off at.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.