Rails 4 Sum by Model Method

ε祈祈猫儿з 提交于 2019-12-04 16:23:55

问题


In my app, I have a User model, with a goal_ytd method, which performs some calculations.

In a controller, I have a variable @users that might be User or an ActiveRecord::Relation of users, and I would like to sum all of the @users's goal_ytds.

My first inclination was:

@users.sum(&:goal_ytd)

Which threw a deprecation warning in both cases because using sum on an ActiveRecord::Relation is going away in Rails 4.1.

So, I changed the code to:

@users.to_a.sum(&:goal_ytd)

Which then threw a NoMethodError because, in a certain circumstance, @users is assigned by @users = User and User has no to_a method.

Assigning @users using @users = User.all throws a deprecation warning because Relation#all is also deprecated.

Is there a way to get all Users as an array? Is there a better way?


回答1:


On Rails 4.1

If goal_ydt is a column in the users table:

@users.sum(:goal_ydt)

If goal_ydt is a method in User class:

@users.to_a.sum(&:goal_ydt)



回答2:


I like to use a combination of map and sum

@users.map(&:goal_ydt).sum



回答3:


You should not use enumerable methods here. Use sum which is defined on ActiveRecord::Relation and takes symbol as parameter. The main difference is that it will perform SUM query in your database, so it is much faster than pulling all the records form db. Also if any of your record has blank value for given field, enumerable sum will throw an error, while ActiveRecord's one will not. In short:

@users.sum(:goal_ydt)  

EDIT:

However since goal_ydt is not a field but a method, you have no choice but to loop over the models. The way I usually do this is by using scoped method:

@users.scoped.sum(&:goal_ydt)



回答4:


The issue here is rooted in a fundamental misunderstanding of the Relation#all deprecation. While Relation#all is deprecated, Model#all is not. Therefore:

@users = User.all

is still perfectly valid, while:

@users = User.where(first_name: "Mike").all

is deprecated.

So the end solution looks like:

@users = User.all
unless current_user.admin?
  @users = @users.where(company_id: current_user.company_id)
end
@users.to_a.sum(&:goal_ytd)

A new question would be: How do I sum all the users goals, preferably in one line, without loading them all into memory? I suppose that's for another day.



来源:https://stackoverflow.com/questions/25274845/rails-4-sum-by-model-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!