Rails:独特用户的三条最新评论

时间:2010-05-25 01:44:01

标签: ruby-on-rails ruby sqlite postgresql activerecord

我将在命名范围内添加什么:by_unique_users以便我可以执行Comment.recent.by_unique_users.limit(3),并且每个用户只能获得一条评论?

class User
  has_many :comments
end

class Comment
  belongs_to :user
  named_scope :recent, :order => 'comments.created_at DESC'
  named_scope :limit, lambda { |limit| {:limit => limit}}
  named_scope :by_unique_users
end

on sqlite named_scope:by_unique_user,:group => “user_id”有效,

但是它会在postgres上出类拔萃,后者会在生产中部署 PGError:错误:列“comments.id”必须出现在GROUP BY子句中或用于聚合函数

3 个答案:

答案 0 :(得分:6)

Postgres与MySQL和SQLite在处理GROUP BY的方式上有所不同。从本质上讲,它非常严格。假设你有。

id name
1  foo
2  bar
2  baz

然后你正在做GROUP BY id。 MySQL假设您只想丢弃除名字之外的所有名称。所以它会产生。

id name
1  foo
2  bar

然而,在这种情况下,Postgres不会猜测分组方法。它需要您希望如何对其他列进行分组的具体说明。它为此目的提供了所谓的聚合函数,在这种情况下,您正在寻找一个首先采用的函数。我找不到这样做的功能,但也许min()max()可以作为一个功能。在这种情况下,您需要使用:select => 'min(comments.id), min(comments.some_other_column)',除了user_id之外,您应该为每个列执行此操作。然后你可以使用:group => 'user_id'没有问题。

顺便说一句,min()max()接受字符串,而不只是数字,所以它们应该适用于任何列。如果你想真正采用的第一个,那么google for“postgres aggregate first”来找到一些实现,或者使用postgres数组。虽然这会破坏与mysql和sqlite的兼容性。

<强>更新

另一方面,如果获取最近的评论并不是太昂贵,那么让ruby处理独特的用户部分。

unique_comments = []
Comment.recent.each do |comment|
  unless unique_comments.find{|c| c.user_id == comment.user_id}
    unique_comments << comment
  end
  break if unique_comments.size > 2
end

现在,您最多有3条来自不同用户的评论。

答案 1 :(得分:0)

命名范围可能不起作用,但您可以强制Rails进行手动查询(来自Geek Skillz)。

Item.find( :all, :order => 'comments.created_at DESC', :select => 'DISTINCT user' )[0, 3]

答案 2 :(得分:0)

通常,订单子句如下所示:

named_scope :recent, :order => 'created_at DESC'

您可能想尝试一下。