Параметры 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
- указывает тип данных параметра и соответственно форматирует его.
Я смог найти некоторые связанные вопросы
Ответы
Ответ 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
, который будет закрывать защищенные функции для публики (в этом модуле будут доступны функции с функциями.)
Надеюсь, что это поможет.