Rails / ActiveRecord: можно ли выполнить этот запрос без передачи строки SQL в #order? - PullRequest
0 голосов
/ 16 февраля 2019

У меня есть две модели 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 здесь .Я думаю, что это в основном то же самое, что и ORDER BY COUNT(Id):

SELECT COUNT(Id), Country
FROM Customer
GROUP BY Country
ORDER BY COUNT(Id) DESC

Можно ли выполнить тот же запрос, не передавая строку SQL?Можно ли это сделать только с помощью интерфейса запросов ActiveRecord?

1 Ответ

0 голосов
/ 16 февраля 2019

Если вы посмотрите в журнал запросов, вы увидите что-то вроде:

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), или любой из других распространенных нестроковых альтернатив.AFAIK, вы должны использовать строку, но вы можете обернуть ее в Arel.sql, чтобы предотвратить будущие проблемы с устареванием:

Label.joins(:issues)
     .group(:name)
     .order(Arel.sql('count_id desc'))
     .count(:id)
     .take(10)

Нет никаких гарантий по этому поводу, поэтому, если вы ее используете, вы должны включить что-то в свойнабор тестов для выявления любых проблем, если поведение изменится в будущем.

...