搜索多个列 - Rails

use*_*136 17 search ruby-on-rails conditional-statements

我目前正在为我的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
Run Code Online (Sandbox Code Playgroud)

现在搜索很好,但我的问题是如果game_name中有一个记录中有'playstation'字样的记录,它将在那里完成搜索.它只返回该记录,而不是所有存储在控制台中的"playstation"的游戏.现在我明白这是因为我的条件中有'或',但我不知道另一种选择.'AND'要求所有条件匹配或根本不返回.什么是我可以使用AND和OR的替代方案?非常感谢帮助.

如果有一个解决方案有单独的搜索框和条目,那就没问题,我不一定要求搜索根据一个搜索表单找到所有搜索框.

Jef*_*eil 34

如果我正确理解你的问题,那么你的SQL对你正在尝试做的事情看起来很好.OR子句将返回column1,column2或column3中匹配的所有记录.它不会在第一场比赛中停止.我确实看到你的参数存在问题,因为第一个你正在使用LIKE和%,但在后两个你不是,也许这就是你的问题来自哪里.

这应该是你的发现(%左右第二次和第三次搜索)?

find(:all, :conditions => ['game_name LIKE ? OR genre LIKE ? OR console LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%"])
Run Code Online (Sandbox Code Playgroud)

或者更好地使用DRY版本(上面不适用于Rails 4.2+):

Item.where('game_name LIKE :search OR genre LIKE :search OR console LIKE :search', search: "%#{search}%")
Run Code Online (Sandbox Code Playgroud)

  • @items = Item.where('game_name LIKE :search OR 类型 LIKE :search OR console LIKE :search', search: "%#{search}%").order(:name) (2认同)

sun*_*nil 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)
Run Code Online (Sandbox Code Playgroud)

它会给你相同的结果.

谢谢


Joh*_*ard 9

我认为这是一个更清洁的解决方案.这允许您更轻松地添加/删除列.

key = "%#{search}%"
columns = %w{game_name genre console}
@items = Item.where(
  columns
    .map {|c| "#{c} like :search" }
    .join(' OR '),
  search: key
)
Run Code Online (Sandbox Code Playgroud)


pet*_*ter 6

在模型的所有字段中搜索的更通用的解决方案是这样的

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

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

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

你只需要这样称呼它

Model.search_in_all_fields "test"
Run Code Online (Sandbox Code Playgroud)

在你开始之前..,不,sql注入在这里可能不起作用,但仍然更好更短

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