Я создал приложение блога w/рубин на направляющих, и я пытаюсь реализовать функцию поиска. Приложение блога позволяет, чтобы пользователи отметили сообщения. Теги создаются в их собственной таблице и belong_to :post
. Когда тег создается, так запись в таблице тега, где название тега является tag_name и связанный post_id. Теги являются строками.
Я пытаюсь позволить пользователю искать любое слово tag_name в любом порядке. Вот то, что я имею в виду. Позволяет говорят, что конкретное сообщение имеет тег, который является 'контроллером кода Ruby'. В моей текущей функции поиска будет найден тот тег, если пользователь будет искать 'рубин', 'код Ruby', или 'контроллер кода Ruby'. Не будет найдено, вводит ли пользователь в 'рубиновом контроллере'.
По существу то, что я говорю, - то, что я хотел бы, чтобы каждое слово, вводимое в поиск, разыскивалось, не обязательно 'строка', которая вводится в поиск.
Я экспериментировал с обеспечением нескольких текстовых полей, чтобы позволить пользователю вводить в нескольких словах, и также играл вокруг с кодом ниже, но, может казаться, не выполняю вышеупомянутое. Я плохо знаком с рубином и направляющими очень жаль, если бы это - очевидный вопрос и до установки драгоценного камня или плагина, я думал, что проверил бы, чтобы видеть, была ли простая фиксация. Вот мой код:
Посмотреть:/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 %>
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
Модель тега
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
Если я правильно понял вашу проблему, вы хотите вернуть строку, если имена тегов для строки совпадают с одним из слов, переданных в строке запроса.
Вы можете переписать свой метод search
следующим образом:
def self.search(search)
all :conditions => (search ? { :tag_name => search.split} : [])
end
Если вам нужно частичное соответствие, сделайте следующее:
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
Edit 1 Если вы хотите пройти множественный поиск strings тогда:
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
Теперь вы можете выполнять такие вызовы, как:
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
Предостережение:
Поиск с использованием подстановочных знаков LIKE
не очень эффективен (поскольку они не используют индекс). Вам следует подумать об использовании Sphinx (через ThinkingSphinx) ИЛИ Solr (через SunSpot), если у вас много данных.
Похоже, вам нужен полнотекстовый поиск. Лучшая интеграция поиска на данный момент - с Sphinx и плагином Thinking_Sphinx . Я использовал его в нескольких проектах, и его очень легко настроить.
Вам действительно нужно установить sphinx на свой хост, поэтому, если вы используете общий хост, это может вызвать некоторые проблемы.
Вы также можете использовать полнотекстовый поиск в базе данных MyISAM MySQL, но производительность при этом довольно низкая.
После того, как ваш sphinx установлен, вы просто вставляете то, что хотите проиндексировать, в свою модель и вызываете model.search. Результатом будет список объектов модели. Он также поддерживает will_paginate.
Я бы посоветовал взглянуть на Searchlogic , если вы не хотите использовать отдельную полнотекстовую поисковую систему (Ferret, Sphinx и т. Д. ). Он делает простой поиск чрезвычайно простым, хотя вы, возможно, не захотите использовать его в общедоступных местах без тщательного тестирования.
Также проверьте Railscast на нем: http://railscasts.com/episodes/176-searchlogic
Вы можете попробовать настроить хорька , или, если вы действительно гнетете, просто используя рельсы, попробуйте следующее:
# Break the search string into words
words = params[:search].blank? ? [] : params[:search].split(' ')
conditions = [[]] # Why this way? You'll know soon
words.each do |word|
conditions[0] << ["tag_name LIKE ?"]
conditions << "%#{word}%"
end
conditions[0] = conditions.first.join(" OR ") # Converts condition string to include " OR " easily ;-)
# Proceed to find using `:conditions => conditions` in your find
надеюсь это помогает =)