Rails 4 Сумма по методу модели

В моем приложении у меня есть модель 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 как массив? Есть ли лучший способ?

Ответ 1

On Rails 4.1

Если goal_ydt - столбец в таблице пользователей:

@users.sum(:goal_ydt)

Если goal_ydt - метод в классе User:

@users.to_a.sum(&:goal_ydt)

Ответ 2

Вы не должны использовать перечисленные здесь методы. Используйте sum, который определен в ActiveRecord:: Relation и принимает символ как параметр. Основное отличие состоит в том, что он выполнит запрос sum в вашей базе данных, поэтому он намного быстрее, чем вытягивание всех записей db. Кроме того, если какая-либо из вашей записи имеет пустое значение для данного поля, перечислимый sum выдаст ошибку, а ActiveRecord - нет. Короче говоря:

@users.sum(:goal_ydt)  

EDIT:

Однако, поскольку goal_ydt не является полем, а является методом, у вас нет выбора, кроме как перебирать модели. Обычно я делаю это с помощью метода scoped:

@users.scoped.sum(&:goal_ydt)

Ответ 3

Мне нравится использовать комбинацию map и sum

@users.map(&:goal_ydt).sum

Ответ 4

Проблема здесь кроется в фундаментальном непонимании устаревания 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)

Новый вопрос: как я могу суммировать все цели пользователей, желательно в одной строке, не загружая их все в память? Я полагаю, что на другой день.