按注释排序时的范围主题查询

时间:2013-01-29 16:08:22

标签: ruby-on-rails

我正在尝试按最近的评论设置主题索引的顺序。这是有效的:

Topic.joins(:comments).order("comments.created_at desc")

但它不止一次列出主题。

有没有办法将每个主题的显示时间限制为一个?

2 个答案:

答案 0 :(得分:3)

好的,发生了这样的事情:当您加入评论时,每个评论会得到一个数据库行(如果主题上有多个评论),则表示每个主题记录的多个副本。

要解决此问题,您需要使用分组,以便每个主题只有一个结果。要分组的是您要返回的模型的ID(topics.id)。现在,还有更多内容 - 因为每个结果仍然有多个注释,每个结果也有多个created_at值,因此(为了按照它进行排序),您需要告诉数据库使用哪个。

这是通过某种聚合函数完成的。我猜你想要最新的评论是决定订单的评论。如果这是真的,代码将是这样的:

Topic.joins(:comments).select('topics.*, max(comments.created_at) as last_comment').group('topics.id').order('last_comment desc')

自定义选择包括您需要的常用数据(关于主题对象的所有内容 - topics.*)以及聚合函数(max(),顾名思义返回最大的可能值。)用于评论的创建日期。更新的日期更大,因此这将是最新评论的创建日期戳。该结果的别名为last_comment(使用as),因此您可以在.order调用中引用它。

答案 1 :(得分:2)

我找到解决问题的最优雅的方法是将touch添加到评论模型中的多态关联中:

belongs_to :commentable, :polymorphic => true, touch: true

如果您没有使用多态关联,可以使用:

belongs_to :topic, touch: true

然后,我所要做的就是将主题模型中的默认范围更改为updated_at

default_scope order: 'topics.updated_at DESC'

touch添加到评论意味着每次向主题添加评论时,它都会更新主题中的updated_at列。

在我正在使用的控制器中:

@topics = Topic.order(sort_column + " " + sort_direction).paginate(:per_page => 20, :page => params[:page])

Topic.all或其他东西也可以在那里工作。

感谢我的超级朋友阿兰向我指出这一点。