获取 Rails 模型中关联列的总和

Ric*_*wis 3 ruby ruby-on-rails associations ruby-on-rails-3

我的模型是这样设置的

class User < ActiveRecord::Base
  attr_accessible :name
  has_many :predictions

end

class Prediciton < ActiveRecord::Base
  attr_accessible :user_id, :score
  belongs_to :user
end
Run Code Online (Sandbox Code Playgroud)

我想要做的是为每个用户获取分数列中所有值的总和。

到目前为止,我已经提出了这一点:

<% @user.each do |u| %>
 <% u.predictions.each do |h| %>
  <%= u.name %><%= h.score %>

 <% end %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

但我的控制器只是

@user = User.all
Run Code Online (Sandbox Code Playgroud)

我在想这样的事情可能有用吗?

@user = User.all
@scores = @user.predictions.where("fixture_date <= ?", Date.today).sum(:score)
Run Code Online (Sandbox Code Playgroud)

但事实并非如此。我是否以错误的方式接近这个?

Mat*_*tzi 5

向用户添加总分:

class User < ActiveRecord::Base
  attr_accessible :name
  has_many :predictions

  def sum_score
    predictions.where("fixture_date <= ?", Date.today).sum(:score)
  end
end
Run Code Online (Sandbox Code Playgroud)

鉴于:

<% @user.each do |u| %>
  <%= u.name %><%= u.sum_score %>
<% end %>
Run Code Online (Sandbox Code Playgroud)


max*_*max 5

接受的答案实际上并不是那么好,因为它给出了 N+1 查询问题,因为获取的每一行都会导致查询获取总和。它不允许您按总量订购。

您想要的是执行自定义选择:

@users = User.joins(:predictions)
    .where("fixture_date <= ?", Date.today)
    .select('users.*, SUM(predications.score) AS total_score')
    .group('users.id')
Run Code Online (Sandbox Code Playgroud)

这将返回一个包含完整用户记录的 ActiveRecord::Relation 对象。

irb(main):031:0> @users.each { |u| puts "User #{u.id} has a total score of #{u.total_score}"}
User 2 has a total score of 2
User 1 has a total score of 5
=> [#<User id: 2, email: nil, password_digest: nil, created_at: "2018-09-03 06:04:57", updated_at: "2018-09-03 06:04:57">, #<User id: 1, email: nil, password_digest: nil, created_at: "2018-09-03 06:01:45", updated_at: "2018-09-03 06:01:45">]
Run Code Online (Sandbox Code Playgroud)

正如您从示例中看到的,ActiveRecord 实际上会为您获取的任何其他列神奇地创建访问器。

您可以使用该列通过应用进行排序.order

@users = User.joins(:predictions)
    .where("fixture_date <= ?", Date.today)
    .select('users.*, SUM(predications.score) AS total_score')
    .group('users.id')
    .order('total_score DESC')
Run Code Online (Sandbox Code Playgroud)

总而言之,你会得到类似的东西:

class User < ActiveRecord::Base
  has_many :predictions

  def self.ordered_by_score
    self.joins(:predictions)
        .where("fixture_date <= ?", Date.current)
        .group('users.id')
        .order('total_score DESC')
  end
end
Run Code Online (Sandbox Code Playgroud)