Rails Arel选择不同的列

Jer*_*iko 11 activerecord ruby-on-rails arel

我用新scope方法(Arel 0.4.0,Rails 3.0.0.rc)轻微阻止了

基本上我有:

一个topics模型,它has_many :comments和一个comments模型(带有一topic_id列)belongs_to :topics.

我正在尝试获取"热门话题"的集合,即最近评论过的主题.目前的代码如下:

# models/comment.rb
scope :recent, order("comments.created_at DESC")

# models/topic.rb
scope :hot, joins(:comments) & Comment.recent & limit(5)
Run Code Online (Sandbox Code Playgroud)

如果我执行Topic.hot.to_sql,则触发以下查询:

SELECT "topics".* FROM "topics" INNER JOIN "comments"
ON "comments"."topic_id" = "topics"."id"
ORDER BY comments.created_at DESC LIMIT 5
Run Code Online (Sandbox Code Playgroud)

这样可以正常工作,但它可能会返回重复的主题 - 如果主题#3最近被多次评论过,则会多次返回.

我的问题

我将如何回归一组独特的主题,记住我仍然需要访问该comments.created_at领域,以显示最后一篇文章的持续时间?我会想象一下distinct或者是什么group_by,但我不太清楚如何最好地去做.

非常感谢任何建议/建议 - 我已经添加了100个代表奖金,希望很快能找到一个优雅的解决方案.

Har*_*tty 5

解决方案1

这不使用Arel,而是使用Rails 2.x语法:

Topic.all(:select => "topics.*, C.id AS last_comment_id, 
                       C.created_at AS last_comment_at",
          :joins => "JOINS (
             SELECT DISTINCT A.id, A.topic_id, B.created_at
             FROM   messages A,
             (
               SELECT   topic_id, max(created_at) AS created_at
               FROM     comments
               GROUP BY topic_id
               ORDER BY created_at
               LIMIT 5
             ) B
             WHERE  A.user_id    = B.user_id AND 
                    A.created_at = B.created_at
           ) AS C ON topics.id = C.topic_id
          "
).each do |topic|
  p "topic id: #{topic.id}"
  p "last comment id: #{topic.last_comment_id}"
  p "last comment at: #{topic.last_comment_at}"
end
Run Code Online (Sandbox Code Playgroud)

确保索引表中的created_attopic_idcomments.

解决方案2

last_comment_idTopic模型中添加一列.last_comment_id创建评论后更新.此方法比使用复杂SQL确定最后一条注释要快得多.

例如:

class Topic < ActiveRecord::Base
  has_many :comments
  belongs_to :last_comment, :class_name => "Comment"
  scope :hot, joins(:last_comment).order("comments.created_at DESC").limit(5)
end

class  Comment
  belongs_to :topic

  after_create :update_topic

  def update_topic
    topic.last_comment = self
    topic.save
    # OR better still
    # topic.update_attribute(:last_comment_id, id)
  end
end
Run Code Online (Sandbox Code Playgroud)

这比运行复杂的SQL查询以确定热门主题更有效.