【发布时间】:2011-01-14 21:16:32
【问题描述】:
我知道预处理语句,但如果我使用的是原始 SQL,ActiveRecord 是否可以手动转义值?
这样的东西会很好:
self.escape("O'Malley") # O\'Malley
【问题讨论】:
标签: ruby-on-rails
我知道预处理语句,但如果我使用的是原始 SQL,ActiveRecord 是否可以手动转义值?
这样的东西会很好:
self.escape("O'Malley") # O\'Malley
【问题讨论】:
标签: ruby-on-rails
你可以这样做:
Dude.sanitize("O'Malley")
或
Dude.connection.quote("O'Malley")
两者的结果相同:=> "'O''Malley'"
【讨论】:
sanitize 函数已被删除,取而代之的是 sanitize_sql。
Model.connection.quote 按预期工作(用单引号括起来,双单引号任何单引号)。 sanitize_sql 在所示示例中什么都不做(它可能会清理其他内容,但不会转义单引号)
快速浏览 ActiveRecord 源代码揭示了其用于清理 [string, bind_variable[, bind_variable]] 类型的 sql 语句的方法“sanitize_sql_array”
你可以直接调用它:
sql = ActiveRecord::Base.send(:sanitize_sql_array, ["insert into foo (bar, baz) values (?, ?), (?, ?)", 'a', 'b', 'c', 'd'])
res = ActiveRecord::Base.connection.execute(sql)
【讨论】:
sanitize_sql_array 及其表亲仍然不是公共 API 的一部分。有没有方便的公共等价物?
您可以轻松地使用 mysql2 gem 来执行此操作:
irb(main):002:0> require 'rubygems'
=> true
irb(main):003:0> require 'mysql2'
=> true
irb(main):004:0> Mysql2::Client.escape("O'Malley") # => "O\\'Malley"
=> "O\\'Malley"
或者如果使用早期的 mysql(不是 mysql2)gem:
irb(main):002:0> require 'rubygems'
=> true
irb(main):003:0> require 'mysql'
=> true
irb(main):004:0> Mysql.escape_string("O'Malley")
=> "O\\'Malley"
这将允许您转义任何您想要的内容,然后插入到数据库中。您也可以使用 sanitize 方法在 Rails 应用程序中的大多数模型上执行此操作。例如,假设您有一个名为 Person 的模型。你可以的。
Person.sanitize("O'Malley")
这应该可以解决问题。
【讨论】:
Mysql2::Client.escape("O'Malley") # => "O\\'Malley"
如果您不希望在使用@konus 发布的解决方案时出现额外的单引号包裹您的字符串,您可以这样做:
Dude.connection.quote_string("O'Malley")
这将返回 "O\'Malley" 而不是 "'O\'Malley'"
【讨论】:
quote_string 将取决于正在使用的特定 ActiveRecord 适配器。对于 mysql2 适配器和抽象 mysql 适配器,quote 调用 quote_string 获取字符串值并将结果用引号括起来。您是否在考虑某种多字节注入或其他?谢谢。
即使使用Model.find_by_sql,您仍然可以使用问号作为转义值的形式。
只需传递一个数组,其中第一个元素是查询,后续元素是要替换的值。
Rails API 文档中的示例:
Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
【讨论】:
INSERT IGNORE 并且我正在更新一个语句中的多个记录以提高性能。
如果有人正在寻找@jemminger 解决方案的更具体示例,这里是批量插入:
users_places = []
users_values = []
timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S')
params[:users].each do |user|
users_places "(?,?,?,?)"
users_values << user[:name] << user[:punch_line] << timestamp << timestamp
end
bulk_insert_users_sql_arr = ["INSERT INTO users (name, punch_line, created_at, updated_at) VALUES #{users_places.join(", ")}"] + users_values
begin
sql = ActiveRecord::Base.send(:sanitize_sql_array, bulk_insert_users_sql_arr)
ActiveRecord::Base.connection.execute(sql)
rescue
"something went wrong with the bulk insert sql query"
end
这里是reference to sanitize_sql_array method in ActiveRecord::Base,它通过转义字符串中的单引号来生成正确的查询字符串。例如,妙语“不要让他们让你失望”将变成“不要让他们让你失望”。
【讨论】: