因此,我有一个餐厅模型,一个餐厅有很多评论,每个评论的评分都为1-5。我有一个功能,允许用户按最低评分过滤餐馆列表,但是目前,它在过滤之前将所有餐馆都抢了下来,然后使用Ruby select语句消除了我不想要的餐馆。我想将其切换到一个更干净的解决方案,该解决方案可以让SQL进行过滤,但是在弄清楚如何使用范围进行处理时遇到了困难。
我已经知道了,但这给了我一个“滥用聚合函数AVG()”的错误:
scope :min_rating, -> (rating) { joins(:reviews).where('AVG(reviews.rating) > ?', rating) if rating}
此范围的正确语法是什么?
答案 0 :(得分:2)
计算平均值时,您需要.group("restaurants.id")
或类似的内容告诉它要整理哪些评论集,然后将其移至.having
条件(在该分组之后应用):< / p>
scope :min_rating, -> (rating) { joins(:reviews).group("restaurants.id").having('AVG(reviews.rating) > ?', rating) if rating }
但是,这是一个很好的例子,说明了对数据进行非规范化可能是合理的-在average_rating
上添加restaurants
列,并在每次保存评论时重新计算。与分组计算不同,该列可以建立索引并进行有效过滤-以存储评论为代价;这是一个权衡。