在Ruby on Rails中搜索 - 如何搜索输入的每个单词而不是确切的字符串?

bga*_*oci 9 ruby search ruby-on-rails

我已经在rails上构建了一个带ruby的博客应用程序,我正在尝试实现搜索功能.博客应用程序允许用户标记帖子.标签是在自己的表格中创建的belong_to :post.创建标记时,标记表中的记录也是如此,其中标记的名称为tag_name并由post_id关联.标签是字符串.

我试图允许用户以任何顺序搜索任何单词tag_name.这就是我的意思.让我们说一个特定的帖子有一个标签是'红宝石代码控制器'.在我当前的搜索功能中,如果用户搜索"ruby","ruby code"或"ruby code controller",则会找到该标记.如果用户键入'ruby controller',则无法找到.

基本上我所说的是我希望在搜索中输入的每个单词都被搜索,而不一定是输入到搜索中的"字符串".

我一直在尝试提供多个文本字段以允许用户输入多个单词,并且还在使用下面的代码,但似乎无法完成上述操作.我是ruby和rails的新手很抱歉,如果这是一个明显的问题,在安装gem或插件之前,我想我会检查是否有一个简单的修复.这是我的代码:

查看:/views/tags/index.html.erb

<% form_tag tags_path, :method => 'get' do %>
    <p>
      <%= text_field_tag :search, params[:search], :class => "textfield-search" %>
      <%= submit_tag "Search", :name => nil, :class => "search-button" %>
    </p>
  <% end %>
Run Code Online (Sandbox Code Playgroud)

TagsController

 def index
    @tags = Tag.search(params[:search]).paginate :page => params[:page], :per_page => 5
    @tagsearch = Tag.search(params[:search])
    @tag_counts = Tag.count(:group => :tag_name, 
       :order => 'count_all DESC', :limit => 100)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @tags }
    end
  end
Run Code Online (Sandbox Code Playgroud)

标签模型

class Tag < ActiveRecord::Base
  belongs_to :post
  validates_length_of :tag_name, :maximum=>42
  validates_presence_of :tag_name

  def self.search(search)
    if search
      find(:all, :order => "created_at DESC", :conditions => ['tag_name LIKE ?', "%#{search}%"])
    else
      find(:all, :order => "created_at DESC")
    end
  end

end
Run Code Online (Sandbox Code Playgroud)

Har*_*tty 10

如果我正确读取了您的问题,如果该行的标记名称与查询字符串中传递的单词之一匹配,则您希望返回一行.

您可以search按如下方式重写方法:

def self.search(search)
  all :conditions =>  (search ? { :tag_name => search.split} : [])
end
Run Code Online (Sandbox Code Playgroud)

如果您需要部分匹配,请执行以下操作:

def self.search(str)
  return [] if str.blank?
  cond_text   = str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
  cond_values = str.split.map{|w| "%#{w}%"}
  all(:conditions =>  (str ? [cond_text, *cond_values] : []))
end
Run Code Online (Sandbox Code Playgroud)

编辑1 如果要传递多个搜索字符串,则:

def self.search(*args)
  return [] if args.blank?
  cond_text, cond_values = [], []
  args.each do |str|
    next if str.blank?  
    cond_text << "( %s )" % str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
    cond_values.concat(str.split.map{|w| "%#{w}%"})
  end
  all :conditions =>  [cond_text.join(" AND "), *cond_values]
end
Run Code Online (Sandbox Code Playgroud)

现在您可以拨打电话,例如:

Tag.search("Ruby On Rails")

Tag.search("Ruby On Rails", "Houston")

Tag.search("Ruby On Rails", "Houston", "TX")

Tag.search("Ruby On Rails", "Houston", "TX", "Blah")

Tag.search("Ruby On Rails", "Houston", "TX", "Blah", ....) # n parameters
Run Code Online (Sandbox Code Playgroud)

警告:

通配符LIKE搜索效率不高(因为它们不使用索引).如果你有大量数据,你应该考虑使用Sphinx(通过ThinkingSphinx)或Solr(通过SunSpot).