正确的ActiveRecord加入查询帮助

时间:2010-03-05 23:56:04

标签: ruby-on-rails activerecord

需要一些SQL / ActiveRecord查询帮助。假设我有这个:

Article < ActiveRecord::Base
  has_many :comments
end

Comment < ActiveRecord::Base
  belongs_to :article
end

现在我想显示“最近讨论”文章的列表 - 这意味着我想要提取所有文章并包含添加到每个文章的最后一条评论。然后我想根据评论的created_at属性对这个文章列表进行排序。

我已经看过关于包含/加入的Railscast - 非常好,但仍然有点难过。

我想我想使用一个named_scope,就是这个效果:

Article < ActiveRecord::Base
  has_many :comments

  named_scope :recently_commented, :include => :comments, :conditions => {   some_way_to_limit_just_last_comment_added }, :order => "comments.created_at DESC"
end

使用MySQL,Rails 2.3.4,Ruby 1.8.7

有什么建议吗? :)

2 个答案:

答案 0 :(得分:0)

你有两个解决方案。

1)您将n recent视为n last。然后你不需要任何花哨的东西:

Article < ActiveRecord::Base   
  has_many :comments

  named_scope :recently_commented, :include => :comments, 
                :order => "comments.created_at DESC",
                :limit => 100 
end

Article.recently_commented # will return last 100 comments

2)你将近期视为最后x个持续时间。

为了清楚起见,我们将最近定义为过去2小时内添加的内容。

Article < ActiveRecord::Base   
  has_many :comments

  named_scope :recently_commented, lambda { { 
                    :include => :comments, 
                    :conditions => ["comments.created_at >= ?", 2.hours.ago]
                    :order => "comments.created_at DESC",
                    :limit => 100 }} 

end

Article.recently_commented # will return last 100 comments in 2 hours

注意以上代码会急切加载与每篇所选文章相关的评论。 如果您不需要急切加载,请使用:joins代替:include

答案 1 :(得分:0)

你必须为此做一些额外的SQL:

named_scope :recently_commented, lambda {{
  :select => "articles.*, IFNULL(MAX(comments.created_at), articles.created_at) AS last_comment_datetime",
  :joins => "LEFT JOIN comments ON comments.article_id = articles.id",
  :group => "articles.id",
  :conditions => ["last_comment_datetime > ?", 24.hours.ago],
  :order => "last_comment_datetime DESC" }}

你需要使用:join而不是:include否则Rails会忽略你的:select选项。另外,不要忘记使用:group选项来避免重复记录。您的结果将包含#last_comment_datetime访问者,该访问者将返回上次评论的日期时间。如果文章没有评论,它将返回文章的created_at。

编辑:命名范围现在使用lambda