Ответ 1
On Rails 4.1
Если goal_ydt
- столбец в таблице пользователей:
@users.sum(:goal_ydt)
Если goal_ydt
- метод в классе User
:
@users.to_a.sum(&:goal_ydt)
В моем приложении у меня есть модель User
с методом goal_ytd
, которая выполняет некоторые вычисления.
В контроллере у меня есть переменная @users
, которая может быть User
или ActiveRecord::Relation
of users
, и я хотел бы суммировать все @users
goal_ytd
s.
Мое первое наклонение было:
@users.sum(&:goal_ytd)
В обоих случаях было предупреждено об устаревании, поскольку использование sum
в ActiveRecord::Relation
уходит в Rails 4.1.
Итак, я изменил код на:
@users.to_a.sum(&:goal_ytd)
Что тогда выбрало NoMethodError
, потому что в известном случае @users
назначается @users = User
, а User
не имеет метода to_a
.
Присвоение @users
с помощью @users = User.all
выдает предупреждение об устаревании, поскольку Relation#all
также устарел.
Есть ли способ получить все users
как массив? Есть ли лучший способ?
On Rails 4.1
Если goal_ydt
- столбец в таблице пользователей:
@users.sum(:goal_ydt)
Если goal_ydt
- метод в классе User
:
@users.to_a.sum(&:goal_ydt)
Вы не должны использовать перечисленные здесь методы. Используйте sum
, который определен в ActiveRecord:: Relation и принимает символ как параметр. Основное отличие состоит в том, что он выполнит запрос sum
в вашей базе данных, поэтому он намного быстрее, чем вытягивание всех записей db. Кроме того, если какая-либо из вашей записи имеет пустое значение для данного поля, перечислимый sum
выдаст ошибку, а ActiveRecord - нет. Короче говоря:
@users.sum(:goal_ydt)
EDIT:
Однако, поскольку goal_ydt
не является полем, а является методом, у вас нет выбора, кроме как перебирать модели. Обычно я делаю это с помощью метода scoped
:
@users.scoped.sum(&:goal_ydt)
Мне нравится использовать комбинацию map
и sum
@users.map(&:goal_ydt).sum
Проблема здесь кроется в фундаментальном непонимании устаревания Relation#all
. Пока Relation#all
устарел, Model#all
нет. Поэтому:
@users = User.all
все еще отлично, а:
@users = User.where(first_name: "Mike").all
устарел.
Итак, конечное решение выглядит так:
@users = User.all
unless current_user.admin?
@users = @users.where(company_id: current_user.company_id)
end
@users.to_a.sum(&:goal_ytd)
Новый вопрос: как я могу суммировать все цели пользователей, желательно в одной строке, не загружая их все в память? Я полагаю, что на другой день.