我正在实现一个简单的搜索功能,该功能应检查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注入?
非常感谢!
答案 0 :(得分:22)
我假设您的模型名称是模型 - 只需在执行实际查询时将其替换为您的真实模型名称:
Model.where("name LIKE ? OR last_name LIKE ? OR first_name LIKE ?", "%#{search}%","%#{search}%","%#{search}%")
关于您对SQL注入的担忧 - 两个代码段都不受SQL注入的影响。只要你没有直接将字符串嵌入到WHERE子句中就可以了。易注入代码的一个例子是:
Model.where("name LIKE '#{params[:name]}'")
答案 1 :(得分:12)
虽然选择的答案会起作用,但我注意到如果你试图输入一个搜索“Raul Riera”就会中断,因为它会在两种情况下失败,因为Raul Riera不是我的名字或我的姓。我的名字和姓氏......我通过
解决了这个问题Model.where("lower(first_name || ' ' || last_name) LIKE ?", "%#{search.downcase}%")
答案 2 :(得分:2)
使用Arel,您可以避免使用以下内容手动编写SQL:
Model.where(
%i(name first_name last_name)
.map { |field| Model.arel_table[field].matches("%#{query}%")}
.inject(:or)
)
如果要匹配的字段列表是动态的,这将特别有用。
答案 3 :(得分:0)
最好的方法是:
Model.where("attr_a ILIKE :query OR attr_b ILIKE :query", query: "%#{query}%")
答案 4 :(得分:0)
在模型的所有字段中搜索的更通用的解决方案是这样的
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