帕特里克有一些很好的建议。但我认为他误解了你的要求。当他的查询将帖子加入发布它们的用户时,而不是评论它们的用户。他走在正确的轨道上,而且他在索引方面绝对是正确的。
以下内容不起作用,因为您正在尝试获取评论对象上的帖子。
@post_ids = Comment.all(:select => "DISTINCT post_id",
:conditions => ["user_id = ? AND updated_at > ?",
@userinfo.id, @userinfo.updated_at.to_date.to_time])
@posts = Post.find(@post_ids)
您可以将所有评论映射到帖子 ID。即:Post.find(@post_ids.map{&:post_id})
但是需要两次数据库旅行并为命中实例化评论是低效的。
相反,您应该使用命名范围或其他东西来根据您的标准选择帖子。
class Post < ActiveRecord::Base
...
#this is what you asked for.
named_scope :with_unseen_comments_for_user, lamda do |user|
{
:select => "DISTINCT posts.*", :joins => "INNER JOIN comments,
comments others_comments, users ON (comments.user_id = users.id AND
others_comments.post_id = post.id AND comments.post_id = posts.id",
:conditions => ["users.id = ? AND
comments_posts.updated_at > users.updated_at", user]
}
end
end
#usage:
Post.updated_after_users_last_comment_in_post(@user)
需要复杂的连接语句来创建有效的查询,因为您希望连接工作列出以下内容:
其他评论 <--- post_id - id ---> 帖子 <--- id - post_id ---> 用户评论 <--- user_id - id ---> 用户
假设我的 SQL 是我记得的,这应该检索给定用户发表评论的所有帖子,并且他的最后一篇帖子是在其他人对同一帖子发表评论之前发表的。
无论如何,当用户在多个线程中发帖时,您会遇到问题。因此,您可能需要重新考虑您的关系并更新方法。
例如,如果发生以下情况,您的用户将不会收到关于帖子 A 的新评论的通知:
用户 X 对帖子 A 的评论
用户 Y 对帖子 A 的评论
用户 X 在注意到用户 Y 对帖子 A 发表评论之前评论了帖子 B。
您可以通过在评论中添加 last_seen_at 字段来解决此问题,并在所有者查看评论时更新它。这对于 :after_filter 来说相当简单。事实上,它使命名范围更简单。因为我们不需要将用户记录拖到查询中来比较日期。
named_scope :unseen_comments, lamda do |user|
{
:select => "DISTINCT posts.*", :joins => [:comments, :comments],
:conditions => ["comments.user_id = ? AND
others_comments.updated_at > comments.last_seen_at", user]
}
end
这:joins => [:comments, :comments]
有点奇怪,但它会将评论加入查询中的帖子两次,第二次别名为comments_posts。它没有在 find 或 named_scope 中专门记录,但它使用与关联连接参数相同的语法。