我正在创建一个范围块,它将生成
的内容Letter.join(:people).where("people.lastname = ? OR people.lastname = ?", 'Carter', 'Testname')
我希望能够使我的查询动态化,因此您可以发送任意数量的名称作为结果拉入
Letter.find_person(['Carter', 'Testname'])
我已经找到了两种方法来获得所需的查询,但我不确定它们中的任何一种都非常安全。我想使用上面的问号语法,但我无法弄清楚如何使用它。
1:
peopleArray.each_with_index do |person, index|
# first person in array does not need an "OR" at the front
the_or = index == 0 ? "" : " OR "
# TODO make this statement more secure
whereClause << "#{the_or}people.lastname = '#{person}'"
end
joins(:people).where(whereClause).length
2:
joins(:people).where({"people.lastname" => array})
Rails标准是否保证上述任何一种方法都是安全的?似乎现在任何类型的字符串都可以传递到查询中。有没有人有任何关于如何在运行之前让Rails检查查询的建议?
答案 0 :(得分:2)
答案 1 :(得分:1)
方法2是安全的,因为Rails在从哈希构造子句时会自动清理。
Rails不会清理你为方法1传递的子句。(实际上,Rails无法确定字符串whereClause
的哪个部分是用户输入需要消毒并且是硬编码的,因此正是你的意图。)
如果您将控制台设置为从ActiveRecord活动输出SQL,则可以看到此信息:
> User.where(first_name: "first'name", last_name: "last'name")
User Load (166.9ms) SELECT `users`.* FROM `users` WHERE `users`.`first_name` = 'first\'name' AND `users`.`last_name` = 'last\'name'
> User.where("first_name = 'first'name' AND last_name = 'last'name'")
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE (first_name = 'first'name' AND last_name = 'last'name')
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'name' AND last_name = 'last'name')' at line 1: SELECT `users`.* FROM `users` WHERE (first_name = 'first'name' AND last_name = 'last'name')
要回答你的第二个问题(如何使方法1安全),你应该这样做:
> User.where("first_name = ? AND last_name = ?", "first'name", "last'name")
User Load (165.8ms) SELECT `users`.* FROM `users` WHERE (first_name = 'first\'name' AND last_name = 'last\'name')
正如您所见,where
的后续参数会在结果查询中替换问号,并按顺序进行清理。