Исправлено предупреждение об устаревании «Опасный метод запроса» в «.order».

У меня есть специальный драгоценный камень, который создает запрос AR с входными данными, поступающими из экземпляра elasticsearch.

# record_ids: are the returned ids of the ES results
# order: is the order of the of the ids that ES returns

search_class.where(search_class.primary_key => record_ids).order(order)

Прямо сейчас реализация заключается в том, что я встраиваю строку заказа непосредственно в переменную order, поэтому она выглядит так: ["\"positions\".\"id\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC"] Это работает нормально, но выдает предупреждение об устаревании, которое в конечном итоге не будет работать в rails6.

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "\"positions\".\"id\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC". 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()

Поэтому я попробовал несколько разных подходов, но все они не увенчались успехом.


order = ["\"positions\".\"id\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC"]

# Does not work since order is an array
.order(Arel.sql(order))

# No errors but only returns an ActiveRecord_Relation
# on .inspect it returns `PG::SyntaxError: ERROR:  syntax error at or near "["`
.order(Arel.sql("#{order}"))
# .to_sql: ORDER BY [\"\\\"positions\\\".\\\"id\\\" = 'fcdc924a-21da-440e-8d20-eec9a71321a7' DESC\"]"

order = ['fcdc924a-21da-440e-8d20-eec9a71321a7', ...]

# Won't work since its only for integer values
.order("idx(ARRAY#{order}, #{search_class.primary_key})")
# .to_sql ORDER BY idx(ARRAY[\"fcdc924a-21da-440e-8d20-eec9a71321a7\", ...], id)

# Only returns an ActiveRecord_Relation
# on .inspect it returns `PG::InFailedSqlTransaction: ERROR:`
.order("array_position(ARRAY#{order}, #{search_class.primary_key})")
# .to_sql : ORDER BY array_position(ARRAY[\"fcdc924a-21da-440e-8d20-eec9a71321a7\", ...], id)

Я как бы застрял, так как рельсы заставляют аргументы атрибутов в будущем, и у меня нет возможности отказаться от этого. Поскольку order представляет собой массив, сгенерированный кодом, и у меня есть полный контроль над значениями, мне любопытно, как я могу это реализовать. Может быть, у кого-то была эта проблема, прежде чем дать какую-то полезную информацию или идею?


person Denny Mueller    schedule 28.11.2019    source источник
comment
Об этом спрашивали раньше stackoverflow.com/questions/48897070/. Дополнительная информация github.com/rails/rails/issues/32995.   -  person Sebastian Palma    schedule 28.11.2019
comment
@SebastianPalma Мне известно о ЗАКРЫТОЙ проблеме github, которая не содержит решения для этой конкретной проблемы. Точно так же связанный вопрос SO не дает решения этой проблемы. Я пытаюсь заставить мой конкретный случай работать на основе возможных решений, которые не работают, как написано в вопросе.   -  person Denny Mueller    schedule 28.11.2019
comment
Есть ли причина, по которой вы передаете весь массив заказов? Почему не order[0]?   -  person Sebastian Palma    schedule 28.11.2019
comment
Потому что массив определяет порядок, в котором должны быть упорядочены результаты штампа из базы данных. AR.where(id: some_ids) не гарантирует порядок, и я хочу применить заказ из эластичного результата. В этом примере я использовал только одну запись в массиве, но их также может быть много.   -  person Denny Mueller    schedule 28.11.2019
comment
В любом случае, почему бы вам просто не использовать Arel.sql(order.join(', '))?   -  person Sebastian Palma    schedule 28.11.2019
comment
Проблема заключается в передаче массива в метод Active Record order.   -  person Sebastian Palma    schedule 28.11.2019
comment
Позвольте мне поспать на этом, может быть, я копался в этом неправильно и упустил из виду наиболее очевидное решение :) В качестве примечания: вы можете передать массив в .order. order = ["\"positions\".\"id\" = '430a37b5-953e-476c-ad9e-e7a8b9dd8722' DESC", "\"positions\".\"id\" = 'cf989afa-eabe-4bd2-a8db-79d03eb6fe44' DESC"] даст вам to_sql ORDER BY \"positions\".\"id\" = '430a37b5-953e-476c-ad9e-e7a8b9dd8722' DESC, \"positions\".\"id\" = 'cf989afa-eabe-4bd2-a8db-79d03eb6fe44' DESC   -  person Denny Mueller    schedule 28.11.2019


Ответы (1)


Вы можете попробовать применить Arel.sql к элементам массива, это должно сработать, т.е.

search_class.where(search_class.primary_key => record_ids)
  .order(order.map {|i| i.is_a?(String) ? Arel.sql(i) : i}) 

person spariev    schedule 11.02.2020