Подтвердить что ты не робот

Параметры Escape в объекте запроса, используя ActiveRecord?

Учитывая объект запроса (не AR-модель)

class ComplexQuery
  QUERY = <<-SQL
    ...
  SQL

  def new(param1, param2)
    ...
  end

  def execute
    # format and interpolate parameters into QUERY
    # pass finished SQL to `execute` or `select_all`
  end
end

Как я могу легко избежать всех параметров?

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

  • Используйте raw_connection, который (для меня) возвращает экземпляр PG::Conn и вызывает exec_params. Я не удовлетворен этим, потому что exec_params требует подробного набора аргументов для указания типов данных.
  • include ActiveRecord::Sanitization в моем объекте запроса и используйте один из его удобных методов, например replace_named_bind_variables. Я не удовлетворен этим, потому что replace_named_bind_variables есть protected, и мне нужно использовать send.
  • Вместо этого напишите module. По какой-то причине, когда я include ActiveRecord::Sanitization в модуль, я могу использовать его защищенные методы. Я не удовлетворен этим, потому что я хочу иногда создавать экземпляр объекта запроса, не выполняя его, например. для тестирования.

Включение ActiveRecord::Sanitization в class кажется лучшим решением, но я должен делать что-то неправильно, потому что я должен использовать метод protected.

Я ищу решение, которое:

  • выполняет несколько параметров
  • предназначен для использования пользователями ActiveRecord
  • указывает тип данных параметра и соответственно форматирует его.

Я смог найти некоторые связанные вопросы

4b9b3361

Ответ 1

Лучшим способом, вероятно, является создание подготовленного оператора с использованием исходного драйвера Postgres. К сожалению, ActiveRecord не раскрывает способ сделать это в общем. Они могут добавить это вскоре, когда mysql2 поддерживает подготовленные операторы. Но в то же время, как это сделать с помощью необработанного драйвера PG в рельсах.

http://deveiate.org/code/pg/PG/Connection.html#method-i-prepare

conn = ActiveRecord::Base.connection.raw_connection
conn.prepare('my_query', 'SELECT foo FROM bar WHERE baz=$1 OR baz=$2')
result = conn.exec_prepared('my_query', ['param1', 'param2'])

Обратите внимание на использование $ в качестве символа для указания позиционного параметра. Цифры соответствуют позиции параметра в массиве, который вы передаете на exec_prepared.

Ответ 2

Все методы санитарии уже включены в ActiveRecord::Base в качестве методов класса и должны быть запущены как ActiveRecord::Base#sanitize_***.

Причина в том, что все функции sanitize_* зависят от драйвера и полагаются на объект connection, который, по-видимому, поступает из ActiveRecord::ConnectionHandling.

Контракт ActiveSupport::Concern нажимает на содержимое модуля Sanitization::ClassMethods, чтобы стать классными методами класса/модуля, который включает Sanitization, то есть как они становятся доступными внутри открытого класса ActiveRecord::Base. Они не опубликованы [IMHO], потому что они требуют установления соединения, которое обычно верно для потомков и может быть не для самого ActiveRecord::Base.

Вообще говоря, нет однозначного способа делать то, что задано без соединения (например, не в потоке ActiveRecord::Base.) Цитата для postgres отличается от таковой для mysql.

Подведение итогов: включение ActiveRecord::Sanitization в класс/модуль имеет мало смысла, поскольку вся функциональность уже представлена ​​в ActiveRecord::Base. Как только вы захотите использовать эти функции цитирования без фактического подключения, она, вероятно, должна реализовать свои собственные функции цитирования, сопоставляя их с соответствующими ConnectionAdapter#quote.

В случае, когда предполагается, что соединение должно быть установлено, я хотел бы добавить модуль оболочки к ActiveRecord::Base, который будет закрывать защищенные функции для публики (в этом модуле будут доступны функции с функциями.)

Надеюсь, что это поможет.