Rails:如何将多态关联模型的sum属性添加到检索到的记录中

时间:2014-01-13 05:35:08

标签: ruby-on-rails ruby-on-rails-4 polymorphism polymorphic-associations

我有以下模型结构:嘉年华有许多活动,有很多竞争对手。竞争对手有多态参与者,可以是学生,也可以是团队(有很多学生)。在代码中:

class Carnival < ActiveRecord::Base
  has_many :events
end

class Event < ActiveRecord::Base
  belongs_to :event_type
  belongs_to :division
  has_and_belongs_to_many :genders
  has_and_belongs_to_many :grades
  has_many :competitors
  has_many :students, through: :competitors, :source => :participant, :source_type => 'Student'
  belongs_to :carnival
end

class Competitor < ActiveRecord::Base
  belongs_to :event
  belongs_to :participant, polymorphic: true
  belongs_to :grade
  belongs_to :house
end

class Team < ActiveRecord::Base
  has_one :competitor, :as => :participant
  has_one :event, :through => :competitor
  has_and_belongs_to_many :students
end

class Student < ActiveRecord::Base  
  belongs_to :grade
  belongs_to :house
  belongs_to :gender
  has_many :competitors, :as => :participant
  has_many :events, :through => :competitors
  has_many :carnivals, :through => :events
  has_and_belongs_to_many :teams
end

竞争对手有一个分数属性,因此在运行事件后,会为其分配分数。

我想要的是一系列方法,可以让我所有学生的总分。

Student.with_total_points_for_carnival(c)
Student.with_individual_points_for_carnival(c)
Student.with_team_points_for_carnival(c)

我得到了一些可以提高总分的SQL(虽然我对它如何正常工作有点不舒服,因为我只是偶然发现它):

SELECT 
  name,
  SUM(points) as points
FROM 
  public.students_teams, 
  public.students, 
  public.teams, 
  public.competitors, 
  public.events
WHERE 
  students_teams.team_id = teams.id AND
  students.id = students_teams.student_id AND
  competitors.participant_id = teams.id AND
  events.id = competitors.event_id AND
  carnival_id = 1
GROUP BY
  public.students.id
ORDER BY
  points DESC

这给出了总积分。我的Rails尝试给了我结果,但它们不正确,它们也不是学生记录:

def self.with_total_points_for(carnival)
  Student.
    joins(:competitors, :events, teams: { competitor: :event}).
    where('events.carnival_id = ?', [carnival.id]).
    group('students.id').
    sum('competitors.points')
end

有关如何使其正常工作的任何指导?所以我可以去:

<% Student.with_total_points_for(@carnival).each do |s| %>
  <%= s.name %>: <%= s.total_points %> <br>
<% end %>

更好的是像Student.with_all_points_for这样的功能或范围让我这样做:

<% Student.with_all_points_for(@carnival).each do |s| %>
  <%= s.name %>: <%= s.total_points %> / <%= s.individual_points %> / <%= s.team_points %> <br>
<% end %>

但现在宝贝步骤......

1 个答案:

答案 0 :(得分:0)

我不确定我是否正确地抓住了你的目标,但我认为这可能对你有帮助

将所需字段添加到select

def self.with_total_points_for(carnival)
  Student.
    joins(:competitors, :events, teams: { competitor: :event}).
    where('events.carnival_id = ?', [carnival.id]).
    group('students.id').
    select('students.*, SUM(competitors.points) AS total_points')
end 

一些注意事项:

  1. (我之前没有检查过,但之前有类似问题)如果您使用Postgres,则不应使用students.*,您应该直接列出所有需要的列:select('students.id, students.name, ..., total_points')
  2. (它可能很有用)您可以在select列出所涉及的表格中的任何列,但请记住您在查询中使用group
  3. PS我不确定在一个简单的查询中有一种简单的方法可以获得individual_pointsteam_points。我认为你应该使用子查询来实现这个目的,并将它们插入到主查询中。要小心,因为它可能是对DB的重要请求,并且需要进行优化。