给定查询对象(不是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
Run Code Online (Sandbox Code Playgroud)
我怎样才能方便地逃避所有参数?
我已经成功完成了三种技术,但没有一种方便.
raw_connectionwhich(对我来说)返回一个实例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方法.
我正在寻找一个解决方案:
我能够找到一些相关的问题
我有一个表companies,有两列名为name和address.通过运行以下代码,新数据将插入到表中:
my_name = "my company name"
my_address = "ABC"
query = "INSERT INTO companies (name,address) VALUES ('#{my_name}','#{my_address}');"
ActiveRecord::Base.connection.execute(query);
Run Code Online (Sandbox Code Playgroud)
如果我将my_name值更改"my company name"为"John's company",我将收到语法错误.这是因为查询变为:
"INSERT INTO companies (name,address) VALUES ('John's company','ABC');"
Run Code Online (Sandbox Code Playgroud)
并且在其中'John's company'有一个引号.
鉴于我已经为查询字符串定义使用了双引号,我怎样才能摆脱关于我的值中单引号的错误?
我已经在一段时间内阅读了关于各种SO线程,指南等的内容......但所有答案都是矛盾和矛盾的.
似乎有很多类似的方法,很多答案都说使用不同的方法.
sanitizesanitize_conditionssanitize_sqlsanitize_sql_arraysanitize_sql_for_assignmentsanitize_sql_for_conditionssanitize_sql_hashsanitize_sql_hash_for_assignmentsanitize_sql_hash_for_conditionssanitize_sql_like我正在尝试编写一个"原始查询"适配器,它允许我运行原始的Postgres查询,但允许我插入来自危险用户输入的我自己的参数.
我不能在这几个实例中使用AR,因为我正在进行复杂的纬度/经度计算,聚合函数,复杂子查询等.
到目前为止,我尝试了两种方法:
方法1
对于这种方法,我不知道是否sanitize是上述的最佳选择,或者它是否适用于100%的情况......(我只使用Postgres)
class RawQuery
def exec(prepared, *params)
prepared = query.dup
params.flatten.each_with_index do |p, i|
prepared.gsub!("$#{i + 1}", ActiveRecord::Base.sanitize(p))
end
ActiveRecord::Base.connection.exec_query(prepared)
end
end
Run Code Online (Sandbox Code Playgroud)
琐碎的用法示例(当然通常不会这么简单,或者我只会使用AR):
RawQuery.new.exec('SELECT * FROM users WHERE name = $1', params[:name])
此外,它似乎sanitize代表quote.但根据这篇SO帖子说它只是用单引号包装东西并不安全......所以我不知道.
方法2
我不确定这是否同样安全,但它似乎使用了一个实际的PG准备功能(我假设它是100%安全的).唯一的问题是rails不会将其打印到控制台,也不包括SQL执行时间(这会破坏我的分析工具).
class RawQuery
def prepare(query, *params)
name = "raw_query_#{SecureRandom.uuid.gsub('-', '')}"
connection = ActiveRecord::Base.connection.raw_connection
connection.prepare(name, query)
connection.exec_prepared(name, params)
end
end
Run Code Online (Sandbox Code Playgroud)
使用方式相同:
RawQuery.new.prepare('SELECT * FROM …
我已经尝试使用谷歌来回答这个看似简单的问题,但令我惊讶的是,它没有帮助.
我的rails应用程序中的代码目前正在使用mysql gem的'prepare'方法.切换到mysql2时,会出现错误:
undefined method `prepare' for #<Mysql2::Client::0.......
Run Code Online (Sandbox Code Playgroud)
所以我尝试寻找'prepare'方法的一个版本,但到目前为止这个搜索都没有成功.任何人都可以帮我解决这个问题吗?
编辑:如果这是不可能的,有人可以让我知道是否有办法简单地用mysql2库中的东西参数化我的查询?
出于性能原因,我需要在我的Rails模型中编写一个执行一些任意SQL的新方法:
UPDATE table
SET col1 = ? AND col2 = ?
WHERE id = ?
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用ActiveRecord::Base.connection.execute或ActiveRecord::Base.connection.update使用一串SQL来获得我需要的结果,但是?使用实际参数值替换参数占位符()的正确步骤是什么?是否有一个Rails方法用于将参数插入到SQL语句中,还是应该通过手动插值来完成?后者似乎不安全......