2016-12-23 53 views
0

我有下面的代码,我正在使用基于用户的搜索过滤帖子的结果。我如何确保参数存在,有效和消毒?Rails消毒和验证用户输入where条款

Post.where("title LIKE ? AND cost >= ? AND cost <= ? AND status = 'open'", "%#{search_params[:keywords]}%", 
        "#{search_params[:min] && !search_params[:min].empty? ? search_params[:min] : 0}", 
        "#{search_params[:max] && !search_params[:max].empty? ? search_params[:max] : 999999999}"); 
+0

的'#sanitize_sql_for_conditions'方法应该在这里派上用场 - [see docs](http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html#method-i-sanitize_sql_for_conditions) – Zoran

回答

0

有 - 像往常一样 - 有很多方法可以解决这个问题。

我认为最好的是use a form model。帮助实施此模式的好宝石是virtusreform,但您也可以使用plain ActiveModel

这个想法是表单对象进行验证,如果它无效,控制器可以呈现验证错误。

如果您在网上搜索“Rails form model pattern”或类似内容,您会发现更多文章。下面是另一个看起来很好的例子:https://webuild.envato.com/blog/creating-form-objects-with-activemodel-and-virtus/

在相关说明中,您可能希望将这个复杂查询封装在作用域中,或者 - 如果您的应用程序将要增长 - 甚至是查询对象。请参阅this article以获取更多高级模式,这些模式在更复杂的Rails应用程序中可能具有优势。

关于输入的清理,只要你使用参数绑定而不是手动字符串连接,Rails会自动清理输入以防止SQL注入。如果你想做更多的事情 - 比如从搜索查询或某事中删除停用词。像这样,你可能会更好用预先存在的搜索框架,如sphinx,pg_searchtextacular

0

我会通过组合型数范围有一定的条件解决这个问题:

# in your models/post.rb 
scope :min_cost, ->(cost) { 
    cost = 0 if cost.blank? 
    where('cost >= ?', cost) 
} 
scope :max_cost, ->(cost) { 
    cost = 999_999_999 if cost.blank? 
    where('cost <= ?', cost) 
} 
scope :cost_between, ->(min, max) { min_cost(min).max_cost(max) } 
scope :open, -> { where(status: 'open') } 
scope :search, ->(title) { where("title LIKE ?", "%#{title}%") if title } 

在控制器的使用该作用域是这样的:

Post.open.search(search_params[:keywords]) 
     .cost_between(search_params[:min], search_params[:max])