我试图通过每个评论的数量来订购我的音乐会。音乐会has_many评论。试过这样做
<% @concerts = Concert.all %>
<% @concerts.order(reviews.size).each do |concert| %>
-
-
-
<% end %>
但我收到此错误
未定义的方法`评论&#39;对于 ActiveRecord的::关系:: ActiveRecord_Relation_Concert:0xb5540398&GT;
有什么建议我会如何参考每个音乐会的评论数量?
答案 0 :(得分:3)
不是最好的,但最简单的解决方案是
@concerts = Concert.all.includes(:reviews).sort_by{|concert| concert.reviews.size}.reverse
答案 1 :(得分:2)
另一个答案的替代方案,最终会给你相同的结果集,但副作用会略有不同:
Concert.select("concerts.*, count(reviews.id) review_count")
.joins("LEFT JOIN reviews ON concerts.id = reviews.concert_id")
.group("concerts.id")
.order("review_count")
主要区别在于此查询在使用之前不会立即执行;您将收到一个活动记录关系,就像您在使用任何活动记录查询方法时一样,这意味着您可以进一步细化或添加到查询(假设说)。
另一个区别是此查询不需要急切加载reviews
。根据您的需要,如果您不需要相关评论中的任何信息,此查询将以相当快的速度运行。
就时间/性能而言,使用50个音乐会和43867个评论的数据库(FK上存在索引),两个版本似乎在大约相同的时间内执行(带有急切的加载)。这是我的基准测试结果表(所有结果都以秒为单位):
| # | Sory_by Query | Pure AR Query | No eager loading |
--------------------------------------------------------
| 1 | 2.899806 | 2.840702 | 0.02164 |
| 2 | 3.150556 | 2.818374 | 0.21612 |
| 3 | 2.812867 | 3.025921 | 0.016368 |
| 4 | 3.069562 | 3.055307 | 0.016884 |
| 5 | 2.862722 | 2.680357 | 0.021316 |
|---|---------------|---------------|------------------|
AVG: 2.9591026 | 2.8841322 | 0.0584836 |
正如您所看到的,使用预先加载的两个查询之间没有显着差异,并且使用我上面的查询而没有急切加载的主要区别。显然,确切的结果对您来说会有所不同,但这可以让您了解相对差异。
旁注:
根据您在问题中发布的内容,您似乎想要在ERB视图中编写此查询。我强烈建议将此查询移动到Concert
模型中的方法,并从控制器中该方法的返回创建实例变量,然后视图可以使用该变量。这样你就可以保持一切美好和分离。
修改强>
为了说明我的建议,我将查询放在Concert
模型的类方法中,如下所示:
def self.ordered_by_reviews
return select("concerts.*, count(reviews.id) review_count")
.joins("LEFT JOIN reviews ON concerts.id = reviews.concert_id")
.group("concerts.id")
.order("review_count")
end
您可以从控制器呼叫(与哪个控制器无关):
... other controller code:
@concerts = Concert.ordered_by_reviews
... and so on
然后,您可以根据需要使用@concerts
,并删除@concerts = Concert.all
等内容。
或者,您也可以使用范围来做同样的事情(我相信它会被认为更多Rails-y):
class Concert < ActiveRecord::Base
scope :ordered_by_review, -> { select("concerts.*, count(reviews.id) review_count").joins("LEFT JOIN reviews ON concerts.id = reviews.concert_id").group("concerts.id").order("review_count") }
... rest of class