评论属于Post。
帖子属于Category。
我如何获得每篇帖子的最新更新评论的集合,这些评论都属于一个类别?
我试过这个,但它只给了我一个帖子:
category.posts.joins(:comments).order('updated_at DESC').first
更新
我想要的是每个帖子获取一个提交,每个帖子的最后更新评论。
答案 0 :(得分:5)
Rails并没有做到这一点特别好,特别是Postgres禁止明显的解决方案(由@Jon和@Deefour提供)。
以下是我使用的解决方案,已转换为您的示例域名:
class Comment < ActiveRecord::Base
scope :most_recent, -> { joins(
"INNER JOIN (
SELECT DISTINCT ON (post_id) post_id,id FROM comments ORDER BY post_id,updated_at DESC,id
) most_recent ON (most_recent.id=comments.id)"
)}
...
(DISTINCT ON
是SQL标准的Postgres扩展,因此它不会在其他数据库上工作。)
简要说明:DISTINCT ON
删除除post_id
的第一行以外的所有行。它使用ORDER BY
决定第一行是哪一行,post_id
必须以updated at DESC
开头,然后按id
排序以获取最新版本,然后Comment.most_recent.joins(:post).where("posts.category_id" => category.id)
为打破平局(通常没必要)。
然后你会像这样使用它:
SELECT *
FROM comments
INNER JOIN posts ON (posts.id=comments.post_id)
INNER JOIN (
SELECT DISTINCT ON (post_id) post_id,id FROM comments ORDER BY post_id,updated_at DESC,id
) most_recent ON (most_recent.id=comments.id)
WHERE
posts.category_id=#{category.id}
它生成的查询类似于:
{{1}}
单一查询,非常高效。如果有人能给我一个不太复杂的解决方案,我会欣喜若狂!
答案 1 :(得分:1)
如果您想要收集每个上次更新的评论,您需要将查询基于Comment
,而不是Category
。
Comment.joins(:post).
where("posts.category_id = ?", category.id).
group("posts.id").
order("comments.updated_at desc")
答案 2 :(得分:1)
您基本上要求的是has_many :through
协会。
尝试设置Category
模型,如下所示:
class Category < ActiveRecord::Base
has_many :posts
has_many :comments, through: :posts
end
然后,您只需执行此操作即可获得最近10条更新的评论:
category.comments.order('updated_at DESC').limit(10)
您可以使用Comment
模型上的命名范围使其更具可读性:
class Comment < ActiveRecord::Base
scope :recently_updated, -> { order('updated_at DESC').limit(10) }
end
给你这个查询用于获得相同的10条评论:
category.comments.recently_updated
所以,对于你真正想要的东西,一个类似的解决方案,但是它要求你从Comment
结尾处理你的关联。
首先,在Comment
上设置关联,以便了解其Category
:
class Comment < ActiveRecord::Base
belongs_to :post
has_one :category, through: :post
end
现在您可以像这样查询您的评论:
Comment.order('updated_at desc').joins(:post).where('posts.category' => category).group(:post_id)
有点啰嗦,但它确实有效。
答案 3 :(得分:0)
.first
只抓一个给你。第一个准确。所以放弃.first
。所以改为:
category.posts.joins(:comments).order('updated_at DESC')