使用has_many through语句使用ActiveRecord和Postgres对结果进行排序

时间:2015-01-13 17:13:22

标签: sql ruby-on-rails postgresql activerecord

我在这里有这3个模型:

class User < ActiveRecord::Base
  has_many :parties, foreign_key: 'organizer_id'

  has_many :invitations, foreign_key: 'attendee_id'
end

class Party < ActiveRecord::Base
  belongs_to :organizer, class_name: 'User'

    has_many :invitations
    has_many :attendees, through: :invitations
end

class Invitation < ActiveRecord::Base
  belongs_to :party
  belongs_to :attendee, class_name: 'User'
  belongs_to :inviter, class_name: 'User'
end

我想让所有与会者参加特定的派对,并邀请那些邀请最多人参与的人。

我该怎么做?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

几种可能的解决方案:

脏了

party.attendees.joins(:invitations).select('parties.*', 'COUNT(DISTINCT invitations.id) as invitation_count').group('parties.id').order('invitation_count')

优点:可能有效

缺点:这很丑陋,不解释自己,你最终会找到一个非常难以查询的关系。相反,避免。

稍微清洁

在应用程序级别对其进行排序:

party.attendees.includes(:invitations).sort_by {|att| att.inivtaions.to_a.size }

优点:你做得更清楚

缺点:返回非队列数组而不是关系。仍然需要解释为什么你要调用to_a(以避免N + 1问题)。

最干净的

在与会者表格中添加额外的列invitations_count,并将counter_cache: true添加到邀请模型中的belongs_to :attendee。利润!

party.attendees.order(:invitations_count)

优点:很好,不言自明。无需从数据库加载邀请。易于排队的协会。

缺点:您需要更新所有记录&#39;在开始使用它之前使用counter_cache:

Attendees.includes(:invitations).each { |att| att.invitation_count = att.invitation.to_a.size }

在此之后,rails将负责将列保持与一些与参加者启动相关联。