为什么ActiveRecord为大多数操作生成参数化查询,而不是为find_by生成参数化查询?

Mas*_*son 5 sql sqlite activerecord ruby-on-rails ruby-on-rails-4

我正在研究一个基本的Rails 4.0应用程序,以了解它是如何工作的,而且我遇到了一些我似乎无法弄清楚的东西.我一直在通过ActiveRecord对默认的Sqlite DB进行查询,对于大多数查询,根据调试输出,它似乎生成参数化查询,如下所示:

2.0.0-p247 :070 > file.save
   (0.2ms)  begin transaction
   SQL (0.6ms)  UPDATE "rep_files" SET "report_id" = ?, "file_name" = ?, "updated_at" = ?
   WHERE "rep_files"."id" = 275  [["report_id", 3], ["file_name", "hello.jpg"],
   ["updated_at", Mon, 09 Sep 2013 04:30:19 UTC +00:00]]
   (28.8ms)  commit transaction
Run Code Online (Sandbox Code Playgroud)

但是,每当我使用find_by进行查询时,似乎只是将提供的参数粘贴到生成的SQL中:

2.0.0-p247 :063 > file = RepFile.find_by(report_id: "29", file_name: "1.png")
  RepFile Load (6.2ms)  SELECT "rep_files".* FROM "rep_files" WHERE
  "rep_files"."report_id" = 29 AND "rep_files"."file_name" = '1.png' LIMIT 1
Run Code Online (Sandbox Code Playgroud)

它确实似乎正在逃避参数以防止SQL注入:

2.0.0-p247 :066 > file = RepFile.find_by(report_id: "29", file_name: "';")
  RepFile Load (0.3ms)  SELECT "rep_files".* FROM "rep_files" WHERE
  "rep_files"."report_id" = 29 AND "rep_files"."file_name" = ''';' LIMIT 1
Run Code Online (Sandbox Code Playgroud)

但是,我的理解是,将参数化查询发送到数据库被认为是比尝试转义查询字符串更好的选择,因为参数化选项将导致查询数据完全绕过数据库的解析引擎.

那么这里发生了什么?这是Sqlite适配器中的一些奇怪之处还是生成调试输出的方式?如果ActiveRecord实际上是这样工作的,有什么理由吗?在我看过的任何地方,我找不到任何关于此事的信息.我已经开始查看ActiveRecord代码了,但还没有想出任何东西.

mu *_*ort 3

如果我们查看find_by源代码,我们会看到:

def find_by(*args)
  where(*args).take
end
Run Code Online (Sandbox Code Playgroud)

只是take将 附加limit 1到查询上,所以我们只剩下where. 该where方法可以处理具有各种占位符格式的各种形式的参数,特别是,您可以where像这样调用:

where('c = :pancakes', :pancakes => 6)
Run Code Online (Sandbox Code Playgroud)

当您有一个最好用 SQL 片段表达的复杂查询或多次使用相同值的查询时,使用命名占位符非常有用,因此命名占位符是一个非常有价值的功能。此外,您还可以应用从调用中获得的结果where,并且可以将最终的查询分块构建在多个彼此不了解的方法和作用域中。因此,存在一个问题:多个彼此不了解的事物可以使用相同的命名占位符,并且可能会出现冲突。解决此问题的一种方法是重命名命名占位符以确保唯一性,另一种方法是通过字符串整理手动填充占位符。另一个问题是不同的数据库支持不同的占位符语法。ActiveRecord 选择手动填充占位符。ActiveRecord::Relationwherewhere

摘要:find_by不使用占位符,因为wherewhere使用占位符,因为通过字符串插值来逐步构建查询比跟踪所有占位符和特定于数据库的语法更容易。