Sql 为什么ActiveRecord为大多数操作生成参数化查询,而不是为find_by生成参数化查询?
我正在开发一个基本的Rails 4.0应用程序来了解它是如何工作的,我遇到了一些我似乎无法理解的事情。我一直在通过ActiveRecord查询默认的Sqlite DB,对于大多数查询,根据调试输出,它似乎会生成参数化查询,如下所示:Sql 为什么ActiveRecord为大多数操作生成参数化查询,而不是为find_by生成参数化查询?,sql,ruby-on-rails,sqlite,activerecord,ruby-on-rails-4,Sql,Ruby On Rails,Sqlite,Activerecord,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" = ?,
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
但是,每当我使用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
它似乎在正确地转义参数以防止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
但是,据我所知,将参数化查询发送到数据库被认为是比尝试转义查询字符串更好的选择,因为参数化选项将导致查询数据完全绕过数据库的解析引擎
这是怎么回事?这是Sqlite适配器中的一些奇怪之处还是调试输出的生成方式?如果ActiveRecord实际上是这样工作的,有什么原因吗?我在任何地方都找不到关于这个的任何东西。我已经开始查看ActiveRecord代码,但还没有找到任何答案。如果我们查看,我们会看到:
def find_by(*args)
where(*args).take
end
take
只是将limit 1
添加到查询上,因此我们只剩下where
。where
方法可以用各种占位符格式处理各种形式的参数,特别是,您可以这样调用where
:
where('c = :pancakes', :pancakes => 6)
当您有一个最适合用SQL代码段表达的复杂查询,或者一个多次使用相同值的查询时,使用命名占位符非常好,因此命名占位符是非常有价值的功能。此外,您还可以将where
应用于从where
调用中获得的ActiveRecord::Relation
,并且您可以在多个互不了解的方法和范围中构建最终查询。因此,其中
有一个问题:多个彼此不了解的事物可能会使用同一个命名占位符,并且可能会发生冲突。解决此问题的一种方法是重命名命名占位符以确保唯一性,另一种方法是通过字符串争用手动填充占位符。另一个问题是,不同的数据库支持不同的占位符语法。ActiveRecord已选择手动填充占位符
小结:
find_by
不使用占位符,因为where
不使用占位符,where
不使用占位符,因为通过字符串插值逐段构建查询比跟踪所有占位符和特定于数据库的语法更容易。我现在远离一台安装了Rails的计算机。你能在哪里试试吗?如果查看ActiveRelation源代码,find_by
只调用where
。以下是源代码rails/activerecord/lib/active_record/relation/finder_methods.rb#find_by(*args)where(*args)。结束,我去寻找写答案的链接,但欢迎你来回答。我也看到了来源,并在问之前试过了。果不其然,使用相同的参数调用where将导致相同的查询。同时,我正在查找where的源代码。where
需要处理类似于where('c=:pancakes',:pancakes=>6)
的事情,并且不能保证:pancakes
不会被完全无关的where
调用使用。因此,您必须使用插值或重写命名占位符来确保每个查询的唯一性。