Rails ActiveRecord – 在多个属性上搜索

我正在实现一个简单的搜索function,它应检查username,last_name和first_name中的字符串。 我在旧的RailsCast上看过这个ActiveRecord方法:

http://railscasts.com/episodes/37-simple-search-form

find(:all, :conditions => ['name LIKE ?', "%#{search}%"]) 

但是我如何设置它以便在name,last_name和first name中搜索关键字并返回记录,如果其中一个字段与该术语匹配?

我也想知道RailsCast上的代码是否容易出现SQL注入?

非常感谢!

我假设您的模型名称是Model – 只需在执行实际查询时将其替换为您的真实模型名称:

 Model.where("name LIKE ? OR last_name LIKE ? OR first_name LIKE ?", "%#{search}%","%#{search}%","%#{search}%") 

关于SQL注入的担忧 – 两个代码片段都不受SQL注入的影响。 只要你没有直接将字符串嵌入到WHERE子句中就可以了。 易于注入的代码的示例是:

 Model.where("name LIKE '#{params[:name]}'") 

虽然选定的答案会起作用,但我注意到如果你试图输入一个搜索“Raul Riera”就会中断,因为它会在两种情况下失败,因为Raul Riera不是我的名字或我的姓。是我的第一个姓氏……我这样解决了

 Model.where("lower(first_name || ' ' || last_name) LIKE ?", "%#{search.downcase}%") 

使用Arel,您可以避免使用以下内容手动编写SQL:

 Model.where( %i(name first_name last_name) .map { |field| Model.arel_table[field].matches("%#{query}%")} .inject(:or) ) 

如果要匹配的字段列表是动态的,这将特别有用。

最好的方法是:

 Model.where("attr_a ILIKE :query OR attr_b ILIKE :query", query: "%#{query}%") 

在模型的所有领域中搜索的更通用的解决方案将是这样的

 def search_in_all_fields model, text model.where( model.column_names .map {|field| "#{field} like '%#{text}%'" } .join(" or ") ) end 

或者更好地作为模型本身的范围

 class Model < ActiveRecord::Base scope :search_in_all_fields, ->(text){ where( column_names .map {|field| "#{field} like '%#{text}%'" } .join(" or ") ) } end 

你只需要像这样调用它

 Model.search_in_all_fields "test" 

在你开始..之前,没有,sql注入可能不会在这里工作,但仍然更好,更短

 class Model < ActiveRecord::Base scope :search_all_fields, ->(text){ where("#{column_names.join(' || ')} like ?", "%#{text}%") } end