搜索多个列 - Rails

时间:2012-02-21 15:08:18

标签: ruby-on-rails search 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

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

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

5 个答案:

答案 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