9

我正在实现一个简单的搜索功能,它应该检查用户名、姓氏和名字中的字符串。我在旧的 RailsCast 上看到过这个 ActiveRecord 方法:

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

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

但是我该如何让它在名称、姓氏和名字中搜索关键字,并在其中一个字段与该术语匹配时返回记录?

我还想知道 RailsCast 上的代码是否容易发生 SQL 注入?

非常感谢!

4

5 回答 5

24

我假设您的型号名称是 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]}'")
于 2012-08-05T13:48:26.967 回答
13

虽然选择的答案会起作用,但我注意到如果您尝试输入搜索“Raul Riera”它会中断,因为它在两种情况下都会失败,因为 Raul Riera 既不是我的名字也不是我的姓氏.. 是我的名字和姓氏...我通过这样做解决了

Model.where("lower(first_name || ' ' || last_name) LIKE ?", "%#{search.downcase}%")
于 2014-04-10T00:10:13.790 回答
2

使用 Arel,您可以避免手动编写 SQL,如下所示:

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

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

于 2017-09-14T17:32:09.847 回答
0

最好的方法是:

Model.where("attr_a ILIKE :query OR attr_b ILIKE :query", query: "%#{query}%")
于 2017-06-17T13:47:51.577 回答
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
于 2018-11-09T12:53:50.483 回答