我有两个型号Issue
和Label
。他们有很多关系。
我有一个方法返回指向最多问题的十个标签。
class Label < ApplicationRecord
has_many :tags
has_many :issues, through: :tags
def self.top
Label.joins(:issues)
.group(:name)
.order('count_id desc')
.count(:id)
.take(10)
end
end
它完全符合我的预期,但我想知道是否可以在没有SQL字符串的情况下编写查询。
order('count_id DESC')
令我困惑。 count_id
来自哪里?没有名为count_id
的列。
Label.joins(:issues).group(:name).column_names
#=> ["id", "name", "created_at", "updated_at"]
我发现了一些SQL示例here。我认为它与ORDER BY COUNT(Id)
基本相同:
SELECT COUNT(Id), Country
FROM Customer
GROUP BY Country
ORDER BY COUNT(Id) DESC
是否可以在不传入SQL字符串的情况下执行相同的查询?可以单独使用ActiveRecord查询界面吗?
如果查看查询日志,您会看到如下内容:
select count(labels.id) as count_id ...
您的group
调用(使用任何参数)和count(:id)
调用的组合获取ActiveRecord以将count_id
列别名添加到查询中。我不认为这是在任何地方记录或指定的(至少我可以找到),但如果你足够勇敢地通过Active Record源,你可以看到它发生。
通常,如果添加GROUP BY然后添加count(:x)
,Active Record将添加count_x
别名。这里没有专栏,所以你不能说order(:count_id)
,order(count_id: :desc)
或任何其他常见的非String替代品。 AFAIK,您必须使用字符串,但您可以将其包装在Arel.sql
中以防止将来出现弃用问题:
Label.joins(:issues)
.group(:name)
.order(Arel.sql('count_id desc'))
.count(:id)
.take(10)
对此没有任何保证,所以如果您使用它,您应该在测试套件中包含一些内容,以便在将来行为发生变化时捕获任何问题。