我目前正在为我的rails应用程序编写搜索方法,目前它工作正常。我在game.rb中有以下内容:
def self.search(search)
if search
find(:all, :conditions => ['game_name LIKE ? OR genre LIKE ? OR console LIKE ?', "%#{search}%", "#{search}", "#{search}"])
else
find(:all)
end
end
现在搜索很好,但我的问题是如果game_name中有一个记录中包含'playstation'字样的记录,它将在那里完成搜索。它只返回该记录,而不是所有存储在控制台中的“playstation”的游戏。现在我明白这是因为我的条件中有'或',但我不知道另一种选择。 'AND'要求所有条件匹配或根本不返回。什么是我可以使用AND和OR的替代方案?非常感谢帮助。
如果有一个解决方案有单独的搜索框和条目,那就没问题了,我不一定要求搜索根据一个搜索表单找到所有搜索框。
答案 0 :(得分:32)
如果我正确理解您的问题,那么您的SQL对您正在尝试的内容看起来很好。 OR子句将返回column1,column2或column3中匹配的所有记录。它不会在第一场比赛中停止。我确实看到你的参数存在问题,因为第一个你使用LIKE和%,但在后两个你不是,也许这就是问题的来源。
这应该是你的发现(%左右第二次和第三次搜索)?
find(:all, :conditions => ['game_name LIKE ? OR genre LIKE ? OR console LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%"])
或更好地使用DRY版本(上面不适用于Rails 4.2 +):
Item.where('game_name LIKE :search OR genre LIKE :search OR console LIKE :search', search: "%#{search}%")
答案 1 :(得分:20)
如果您有15列要搜索,那么您将重复键15次。而不是在查询中重复键15次,你可以像这样写:
key = "%#{search}%"
@items = Item.where('game_name LIKE :search OR genre LIKE :search OR console LIKE :search', search: key).order(:name)
它会给你相同的结果。
由于
答案 2 :(得分:9)
我认为这是一个更清洁的解决方案。这允许您更轻松地添加/删除列。
key = "%#{search}%"
columns = %w{game_name genre console}
@items = Item.where(
columns
.map {|c| "#{c} like :search" }
.join(' OR '),
search: key
)
答案 3 :(得分:0)
如果您要像我一样搜索列数组,我认为这是一种更有效的解决方案。
首先也是最重要的是,您可以向模型中添加一个私有函数来创建查询模板:
def self.multiple_columns_like_query(array)
array.reduce('') { |memo, x| #
unless memo == '' #
memo += ' or ' # This is the
end #
memo += "#{x} like :q" # core part
} #
end
比您可以在搜索功能中使用该功能:
def self.search(query)
if fields = self.searched_fields && query
where multiple_like_query(fields), q: "%#{query}%"
end
end
在这里,您还应该将self.searched_fields
定义为字段名称数组。
答案 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