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。 –