Упорядочить по количеству в Rails 6

RuleCategory имеет множество правил. Я хочу перечислить RuleCategories по количеству правил, которые у них есть.

Я использую Rails 5.2.1, но когда я группирую и пытаюсь упорядочить по количеству (*), я получаю сообщение об ошибке, потому что я использую необработанный SQL.

RuleCategory.joins(:rules).where(rules: {edit_status: [Rule::EDIT_STATUS_SYNCHED, Rule::EDIT_STATUS_EDIT]})
.group(:category).order('count(*)').limit(5).pluck(:category, :id).to_a

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL)
called with non-attribute argument(s): "count(*)". Non-attribute arguments will be disallowed
in Rails 6.0. This method should not be called with user-provided values,
such as request parameters or model attributes.
Known-safe values can be passed by wrapping them in Arel.sql(). (called from irb_binding at (irb):2)

Как поместить оператор count в предложение заказа?


person Marlin Pierce    schedule 10.12.2019    source источник


Ответы (1)


Предупреждения об устаревании в рельсах написаны очень хорошо. Обычно они говорят вам, что вы должны сделать, чтобы исправить их. Посмотрите на последнюю строку предупреждения:

Известные безопасные значения можно передать, обернув их в Arel.sql(). (вызывается из irb_binding по адресу (irb):2)

Он говорит вам использовать функцию Arel.sql(), если вы уверены, что ваш код правильный и безопасно использовать необработанный SQL непосредственно в предложении order SQL. Его следует использовать следующим образом:

RuleCategory
  .joins(:rules)
  .where(rules: {edit_status: [Rule::EDIT_STATUS_SYNCHED, Rule::EDIT_STATUS_EDIT]})
  .group(:category)
  .order(Arel.sql('count(*)'))
  .limit(5)
  .pluck(:category, :id).to_a

(Новые строки добавлены только для удобства чтения)

См. часть с пунктом order :

  .order(Arel.sql('count(*)'))

Это должно исправить предупреждение об устаревании.

person edariedl    schedule 13.12.2019
comment
В основном я согласен с тем, что предупреждения об устаревании в рельсах написаны очень хорошо. Однако в этом случае меня интересуют известные безопасные значения, как безопасные от чего? Кроме того, я не нашел хорошей документации по Arel, так что Arel для меня загадка. - person Marlin Pierce; 18.12.2019
comment
На самом деле это тоже говорит: This method should not be called with user-provided values, such as request parameters or model attributes. - Иногда порядок обеспечивается пользовательским вводом, и тогда было бы небезопасно использовать его напрямую. Но в вашем случае это не так, и использовать его как есть абсолютно безопасно. Я предполагаю, что это должно быть защитой от случайного внедрения SQL. - person edariedl; 18.12.2019
comment
Итак, вы думаете, что вы можете передать пользовательский/сетевой ввод методу order, но никогда не Arel.sql, так что последний будет, когда это будет безопасно? - person Marlin Pierce; 19.12.2019
comment
Да, когда это безопасно и вам нужно использовать какую-то функцию SQL в методе order, всегда используйте Arel.sql. Когда вы упорядочиваете какие-либо пользовательские данные, не используйте их и не допускайте их сбоя. - person edariedl; 20.12.2019