1

скажем, у меня есть модель, как это:сумма() или группа() виртуальные атрибуты в Ruby On Rails

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