Rails ActiveRecord - 搜索多个属性
Posted
技术标签:
【中文标题】Rails ActiveRecord - 搜索多个属性【英文标题】:Rails ActiveRecord - Search on Multiple Attributes 【发布时间】:2012-08-02 18:04:55 【问题描述】:我正在实现一个简单的搜索功能,它应该检查用户名、姓氏和名字中的字符串。我在旧的 RailsCast 上看到过这个 ActiveRecord 方法:
http://railscasts.com/episodes/37-simple-search-form
find(:all, :conditions => ['name LIKE ?', "%#search%"])
但是我该如何让它在 name、last_name 和 first name 中搜索关键字并在其中一个字段与该术语匹配时返回记录?
我也想知道 RailsCast 上的代码是否容易被 SQL 注入?
非常感谢!
【问题讨论】:
【参考方案1】:我假设您的型号名称是 Model - 只需在您进行实际查询时将其替换为您的真实型号名称:
Model.where("name LIKE ? OR last_name LIKE ? OR first_name LIKE ?", "%#search%","%#search%","%#search%")
关于您对 SQL 注入的担忧 - 两种代码 sn-ps 都不受 SQL 注入的影响。只要您不直接将字符串嵌入到 WHERE 子句中,就可以了。易于注入的代码示例如下:
Model.where("name LIKE '#params[:name]'")
【讨论】:
如果控制器被更改为传递整个params
而不仅仅是params[:search]
并且在我们的查询中我们使用"%#params[:search]%"
而不是"%#search%"
。这仍然不受 SQL 注入的影响吗?
@Dennis 是的。只要你用?并在查询中传递额外的参数来替换它们就可以了。
谢谢@ErezRabih。那么使用哈希呢?例如。 where(name: params[:name])
这个查询就像一个魅力! (使用活动记录 5)
拥有这三个参数真的很难看。最好这样命名Model.where("x ILIKE :query OR y ILIKE :query", query: "%#params[:query]%")
【参考方案2】:
虽然选择的答案会起作用,但我注意到如果您尝试输入搜索“Raul Riera”,它会中断,因为这两种情况都会失败,因为 Raul Riera 既不是我的名字也不是我的姓氏。我的名字和姓氏......我通过这样做解决了它
Model.where("lower(first_name || ' ' || last_name) LIKE ?", "%#search.downcase%")
【讨论】:
我发现这个答案更有用。谢谢! 使用ILIKE
而不是小写不是更好吗?让数据库处理它。
last_name 或 first_name 等于 nil 时不起作用,如果是,则需要将默认的空字符串值设置为名字和姓氏【参考方案3】:
最好的方法是:
Model.where("attr_a ILIKE :query OR attr_b ILIKE :query", query: "%#query%")
【讨论】:
【参考方案4】:使用 Arel,您可以避免手动编写 SQL,如下所示:
Model.where(
%i(name first_name last_name)
.map |field| Model.arel_table[field].matches("%#query%")
.inject(:or)
)
如果要匹配的字段列表是动态的,这将特别有用。
【讨论】:
你忘记了 .map 行的结束符 ,修改它【参考方案5】:在模型的所有字段中搜索的更通用的解决方案是这样的
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
【讨论】:
以上是关于Rails ActiveRecord - 搜索多个属性的主要内容,如果未能解决你的问题,请参考以下文章
使用 Activerecord、Rails 和 Postgres 查找具有多个重复字段的行
Rails 4,ActiveRecord,查找当前用户未评论的所有帖子
Rails/Arel:选择所有记录作为 ActiveRecord::Relation
如何编写迁移以重命名 Rails 中的 ActiveRecord 模型及其表?