Search code examples
sqlrubysearchruby-on-rails-4tagging

comma separated string with Advance Search


I've added an Advance Search to my Book App using this tutorial. Everything works fine, but now I am trying to find a Book by its Tags.

I got the advance search to work if the user enters one Tag into the :keywords text_field.

Is there a way to search various tags by splitting the keyword string with commas?

(ex: fun, kid stories, action) 
Would allow me to search books with fun OR kids stories OR actions.

How can I search multiple tags via a comma separated string?

Note: I created a search method that I think could help, but I am not sure how to combine it with the single keyword search.

MODEL

class Book < ActiveRecord::Base

  has_many :book_mappings
  has_many :tags, through: :book_mappings

end


class BookMapping < ActiveRecord::Base
  belongs_to :book
  belongs_to :tag
end

class Tag < ActiveRecord::Base

  has_many :book_mappings
  has_many :books, through: :book_mappings

end


class Search < ActiveRecord::Base

  def books
    @books ||= find_books
  end

  def find_books
    books = Book.order(:name)

    ###This works for a single word but NOT if I have multiple tags separated by commas
    books = books.joins(:tags).where("tags.name like ?", "%#{keywords}%") if keywords.present?

    books
  end

  def search(keywords)
     return [] if keywords.blank?
     cond_text = keywords.split(', ').map{|w| "name LIKE ? "}.join(" OR ")    
     cond_values = keywords.split(', ').map{|w| "%#{w}%"}
     all(:conditions =>  (keywords ? [cond_text, *cond_values] : []))
  end

end

VIEWS

<%= form_for @search do |f| %>

  <div class="field">
    <%= f.label :keywords %><br />
    <%= f.text_field :keywords %>
  </div>

<% end %>

Solution

  • Here is a simple solution. Just add a like statement for each keyword.

    To filter books with all the tags

    if keywords.present?
      books = books.joins(:tags)
      keywords.tr(' ','').split(',').each do |keyword|
        books = books.where("tags.name like ?", "%#{keyword}%") 
      end
    end
    

    To filter books with any of the tags

    if keywords.present?
      books = books.joins(:tags)
    
      keyword_names = keywords.split(', ')
      cond_text = keyword_names.map{|w| "tags.name like ?"}.join(" OR ")
      cond_values = keyword_names.map{|w| "%#{w}%"}
    
      books = books.where(cond_text, *cond_values)
    end