1

让我们说我有一个模型是这样的:和(或群体)的虚拟属性在轨道上

class Surface < ActiveRecord::Base 
    attr_accessible :width, :length 

    def area 
    self.width * self.length 
    end 
end 

@surface.area回报的表面的面积。现在,让我们说我有很多表面叫@surfaces,我想总结所有区域。我该怎么做呢?

我最喜欢的解决方案是这样的:

@surfaces.sum(:area) 

但它不工作。那么我怎样才能调用.sum().group()或任何类似的功能在这样的虚拟属性在rails?我想要避免拨打.each do |surface|

在此先感谢。

回答

2

这可以通过Enumerable#reduce方法来实现:

@surfaces.reduce(0){ |sum, surface| sum + surface.area } 
2

sum会很愉快地接受SQL表达式,而不是仅仅列名,因此所有你需要做的就是你的sum方法转化为SQL:

@surfaces.sum('width * height') 
@surfaces.sum('surface.width * surface.height') # If you think other tables might be involved. 

此外,模型中的类方法被混合到关系中(因为范围和类方法实际上是相同的东西),因此您可以添加一个类方法以使用实例方法:

class Surface < ActiveRecord::Base 
    def self.area 
    sum('surface.width * surface.height') 
    end 
    def area 
    self.width * self.length 
    end 
end 

说:

@surfaces.area 

你平时最好让数据库做你的数据繁重,这是他们为了什么,以及他们所擅长的。

+0

感谢您的回复!你的解决方案非常好,但是如果有什么方法可以使虚拟':area'属性成为真正的':width'或':length'属性,我仍然非常有效。所以我可以使用'.sum(:area)'或'.group(:area)',就像我用':width'做的那样。 'width * height'只是一个简单的例子,它应该表示任何计算或者更复杂的函数用于一般目的。 – kernification

+0

抱歉,ActiveRecord不够聪明,无法将任意Ruby代码转换为SQL。 –