it-swarm.com.ru

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

В моем приложении у меня есть модель User с методом goal_ytd, который выполняет некоторые вычисления.

В контроллере у меня есть переменная @users, которая может быть User или ActiveRecord::Relation из users, и я хотел бы суммировать все @usersgoal_ytd.

Мой первый наклон был:

@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 в виде массива? Есть ли способ лучше?

14
J3RN

На Rails 4.1

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

@users.sum(:goal_ydt)

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

@users.to_a.sum(&:goal_ydt)
26
dazonic

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

@users.map(&:goal_ydt).sum
2
Fran Martinez

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

@users.sum(:goal_ydt)  

Правка:

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

@users.scoped.sum(&:goal_ydt)
2
BroiSatse

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

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

0
J3RN