4

UPDATED 6/29/12

I have managed to set up a search and a side bar for filtering results of a search using Sunspot and act-as-taggable with Rails. I was following this tutorial here but I still can't select mutliple filter's at once. When I select a filter the other sub-category names still disappear. What am I missing?

My Original Question was this:

I'm not quite sure how to select multiple facets at once filtering the data. So I have multiple sub categories i.e.(hiking, skiing, climbing, etc.) I want to be able to select hiking and climbing simultaneously so the data shown is only those objects of hiking and climbing. Right now I select one (let's say hiking) and all the other options disappear. Can someone explain?

Below is my code:

Gear Controller

  def index
    @search = Gear.solr_search do
        exclusions = []
        fulltext params[:search]
        exclusions << with(:sub_category_name, params[:name]) if params[:name].present?
        exclusions.compact!
        exclusions = nil if exclusions.empty?
        facet :sub_category_name
        facet :sub_category_name, :exclude => exclusions, :name => :all_categories
        paginate(page: params[:page], :per_page => 15)
    end

    @gears = @search.results
  end 

** Gear Index View**

<div class="gears_container">
    <div class="side_bar_search">
        <%= form_tag gears_path, :method => :get do %>
          <p>
            <%= text_field_tag :keywords, params[:keywords] , class: 'gearsearchbar' %> <%= submit_tag "Search", :name => nil, class: 'btn btn-inverse gearsearchbutton'  %>

         </p>
        <% end %>

    <div class="sidebar_section">Sub Category</div>
    <ul>
    <% for row in @search.facet(:all_categories).rows %>
      <li class="sidebar_options">
        <% if params[:name].present? %>
          <strong><%= row.value %></strong>(<%= link_to "remove", :name => nil %>)
        <% else %>
          <%= link_to row.value, :name => row.value %> (<%= row.count %>)
        <% end %>
      </li>
    <% end %>
    </ul>
</div>
<div c
    <div class="search_results_gear">   
        <% @hits.each do |gear| %>
            <%= render partial: 'gear', locals: {gear: gear} %>
        <% end %>
        <div style="clear:both"></div>
     <%= will_paginate @hits, class: 'flickr_pagination' %>
         </br>
    </div>
</div>

Gear Model

class Gear < ActiveRecord::Base
  attr_accessible :title, :size, :price, :sub_category_id, :user_id, :image, :image_a, :remote_image_url, :color, :year, :latefee, :cancellation, :minrental, :policy, :about, :address, :city, :state, :zip, :sub_category_name
  belongs_to :user
  belongs_to :sub_category
  has_one :category, :through => :sub_category
  has_many :comments, :dependent => :destroy 
  has_many :line_items
  require 'carrierwave/orm/activerecord'
  mount_uploader :image, GearpicUploader
  mount_uploader :image_a, GearpicUploader
  before_destroy :ensure_not_referenced_by_any_line_item
  acts_as_taggable_on :tags

  validates :title, presence: true
  validates :size,  presence: true
  validates :price, presence: true
  validates :sub_category_id, presence: true
  validates :user_id, presence: true

  searchable do
     text :title, :size, :price, :year, :zip, :state, :city, :minrental, :about, :latefee, :color

     text :user_firstname do
          user.firstname
     end

     text :user_lastname do
          user.lastname
     end
     # **Facet Section**   

     string :size, :price, :year, :zip, :state, :city, :minrental, :latefee, :color 

     string :sub_category_name , :multiple => true, :stored => true do
       sub_category.name
     end

     string :category_name do
       category.name
     end
   end

   private
   def ensure_not_referenced_by_any_line_item
     if line_items.empty?
      return true
      else
      errors.add(:base, 'Line Items present')
      return false
     end
   end

end
DaveG
  • 1,203
  • 1
  • 25
  • 45
  • Should I be thinking about this differently? I'm a newbie so if I'm trying to do something with Sunspot that should be done another way let me know...Thanks for the help! – DaveG May 15 '12 at 23:01

1 Answers1

3

It looks like you need to take advantage of the :exclude option for your faceted search.

def index
  @search = Gear.search do
    exclusions = []
    # tags, AND'd        
    if params[:tag].present?
      all_of do
        params[:tag].each do |tag|
          exclusions << with(:sub_category_name, tag)
        end
      end
    end
    exclusions.compact!
    exclusions = nil if exclusions.empty?
    facet :sub_category_name
    facet :sub_category_name, :exclude => exclusions, :name => :all_categories
    paginate(page: params[:page])
  end
  @hits = @search.results
end

So what I've done above, is create an exclusions array to hold the collection of filters. The with() method returns a filter object, so we capture all the filters in the exclusions array. We do the compact! to remove nil objects from the array, and if it's empty, we make it nil (this is due to the limitations of the :exclude option, if you pass it an empty array, it will not work correctly). We then facet on the same :sub_category_name term, excluding the filters, and also give it a name. This facet will give you all the facet categories excluding the selected ones.

Then in your view, when you display the facet options, you use the named :all_categories facet.

@search.facet(:all_categories).rows.each_with_index do |facet, index|
  # This just outputs all the facets, you can add the logic in.
  <li><%= facet.value %> (<%= facet.count %>)</li>
end
vanhowen
  • 153
  • 1
  • 7
  • Vanhowen, thank you for the response. Long awaited :) I adjusted my newest round of code to reflect your response. Right now when I select one sub-category they all become elected (I know this is due to my changes). I tried implementing your code above but when I selected one sub_category and then a second all of the results would disappear. – DaveG Jun 29 '12 at 23:28
  • 1
    It seems like we have two issues here: 1. When you select one sub-category, they all become selected. 2. When you select one sub-category, the results are filtered correctly (even though all categories are selected). But when you select another sub-category, all of the results disappear. To fix this, I would pass an array of sub-category filters from your view to your search method. Then use the array of filters to in your search (the same way the params[:tag].each loop is working above). In your view, you need to check to see if the current row.value exists in the filters array. Make sense? – vanhowen Jul 03 '12 at 18:14
  • Yes, you are correct there are the 2 issues you listed above. Thanks for the response. I'm a new enough programmer that I'm not sure how to piece this together, having not done anything like that before (pass an array from view to method, and then using the array in the search). Any chance you could put some code example up? – DaveG Jul 04 '12 at 05:19