感谢您对此的帮助!我正在研究一个传统的Rails应用程序,我已经检查了一些来源但是无法让它们适合我的情况。在Rails 2.3中,我有一个搜索表单(index.html.erb)和一个控制器(search.rb)。控制器使用搜索字段构建一个字符串,该字符串保存在变量@search_string中。
@search_string = ""
要显示搜索结果,控制器使用:
@location_matches = Location.paginate_by_sql("select * from locations where #{@search_string} order by nickname asc", :page => params[:page], :per_page => 20)
对我进行消毒的最简单方法是什么?我试过了
@location_matches = Location.paginate_by_sql('SELECT * FROM locations WHERE #{@search_string} = ?', @search_string)
这会抛出错误ArgumentError(预期参数hash)。仅供参考,@ search_string使用如下表单字段构建:
FORM
<label for="city">City</label>
<input id="city" name="city" size="30" type="text" value="" />
CONTROLLER
if params[:city] != ""
@search_string << "and city like '%#{params[:city]}%' "
if @first_term == 'y'
@search_string = @search_string.gsub('and ', " ")
@first_term = 'n'
end
end
我很确定各个字段没有正确参数化,而是通过每个字段并尝试修复它,我只是通过调整paginate_by_sql语句来寻找更快的解决方案(我是Rails的新手)我只是想快速修复,因为整个应用程序最终都需要升级。)
修改
我按照Rails, how to sanitize SQL in find_by_sql中的步骤添加了初始化程序。我还将我的陈述改为以下内容。但是,当我运行搜索时,我没有得到任何结果。我还必须删除升序条件,因为它引发了错误。任何想法都非常受欢迎!
初始化程序
class ActiveRecord::Base
def self.escape_sql(clause, *rest)
self.send(:sanitize_sql_array, rest.empty? ? clause : ([clause] + rest))
end
end
控制器
query = Location.escape_sql(["SELECT * from locations WHERE #{@search_string} = ?", params[:@search_string]])
@location_matches = Location.paginate_by_sql(query, :page => params[:page], :per_page => 20)
日志(看起来与返回结果的代码相同)
Parameters: {"city"=>"New York", "commit"=>"Search", "search"=>{"size_category"=>"", "state"=>""}}
答案 0 :(得分:0)
简短的回答是:你真的不能很快这样做。
我建议更新搜索字符串构建器,而不是只创建一个字符串,以构建数组样式的查找器集,例如:["field = ?", param]
例如:
search_string = ""
search_vals = []
if params[:city].present?
search_string << "and city like ? "
search_vals << "%#{params[:city]}%"
end
if params[:whatever].present?
search_string << "and whatever like ? "
search_vals << "%#{params[:whatever]}%"
end
然后,当您想要进行最终搜索时,您可以像这样使用它:
search_string = "SELECT * from locations WHERE #{search_string}"
# turns it into the array-with question-mark syntax
search_query = [search_string] + search_vals
# if paginate_by_sql takes array, you can use it straight up here:
@location_matches = Location.paginate_by_sql(search_query, :page => params[:page], :per_page => 20)
# otherwise use your "escape_sql" variant first
@location_matches = Location.paginate_by_sql(Location.escape_sql(search_query), :page => params[:page], :per_page => 20)