Rails,对模型的所有实例的属性的聚合求和

时间:2016-10-18 16:01:46

标签: ruby-on-rails

我有一个模特频道。相关表有几列,例如点击。

因此Channel.all.sum(:clicks)为我提供了所有频道的点击总和。

在我的模型中,我添加了一个新方法

def test
 123 #this is just an example
end

现在,Channel.first.test返回123

我想要做的是像Channel.all.sum(:test)那样总结所有频道的测试值。

我得到的错误是测试不是一个列,当然不是,但我希望能够构建这个总和。

我怎么能实现这个目标?

4 个答案:

答案 0 :(得分:2)

你可以尝试:

Channel.all.map(&:test).sum

如果点击是模型表的一列,请使用:

Channel.sum(:clicks)

答案 1 :(得分:1)

要解决您的问题,您可以

Channel.all.sum(&:test)

但尝试在数据库层实现它会更好,因为使用Ruby进行处理可能会增加内存和效率。

修改

如果你想通过一个带参数的方法求和:

Channel.all.sum { |channel| channel.test(start_date, end_date) }

答案 2 :(得分:1)

你在这里谈论的是两件截然不同的事情:

ActiveRecord::Calculations.sum对数据库中列的值进行求和:

SELECT SUM("table_name"."column_name") FROM "column_name"

如果您拨打Channel.sum(:column_name),就会发生这种情况。

使用.sum方法

ActiveSupport also extends the Enumerable module

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

这会循环使用内存中的所有值并将它们加在一起。

Channel.all.sum(&:test)

相当于:

Channel.all.inject(0) { |sum, c| sum + c.test }

使用后者会导致严重的性能问题,因为它会将所有数据从数据库中提取出来。

答案 3 :(得分:0)

或者你这样做。

Channel.all.inject(0) {|sum,x| sum + x.test }

您可以将0更改为您希望总和开始的任何值。