Search code examples
ruby-on-railsrubysolrenumssunspot

How Do I Scope Enums in Rails Using Sunspot?


I am trying to use Sunspot (Rails Solr gem) to scope results using an enum I have declared in my model. The relevant portion of my model looks like this:

searchable do
  text :tag_list
  boolean :approved
  integer :perspective
  time :created_at
end

enum perspective: [ :not_applicable, :front, :side_front, :side, :side_back, :back, :above, :below ]

My search block in my controller looks like this:

def index
  //skip scoping if perspective is nil
  params[:perspective] ||= []

  @search = Upload.search do
    with :approved, true
    with :perspective, params[:perspective]
    fulltext params[:tag]
    fulltext params[:search] do
      minimum_match 1
    end
    paginate page: params[:page], per_page: 30
  end
    @uploads = @search.results
    @query = params[:search]
end

And the link I'm using to collect the params looks like this:

<%= link_to upload.perspective.humanize, search_index_path(perspective: Upload.perspectives[upload.perspective]), class: "perspective" %>

Basically I'm trying to set this up so that it returns the results of any combination of all of these criteria after scoping by approved. I've got it working with the text based search criteria, but the scoping by perspective is not working. The search just returns all the results for 0 and none for any other value. Am I missing something about how Sunspot/Solr works with enums? When I do a query such as Upload.where(perspective: 1) I get the proper results, so I'm not sure why this isn't working.

Thanks in advance.


Solution

  • I finally got this one solved. The issue was that although Rails stores the enum value as an integer in the database, it does not retrieve that integer when you call the enum attribute (in this case @upload.perspective). This returns a string corresponding to the name of the value instead ("front", "side", etc. in this case). The problem with this is that in my searchable block I was declaring the perspective field as an integer.

    The solution:

    A method in the model which grabs the enum id integer rather than the name:

    def perspective_id
      Upload.perspectives[self.perspective]
    end
    

    Modifying the searchable block:

    searchable do
      text :tag_list
      boolean :approved
      integer :perspective_id
      time :created_at
    end
    

    And the search block in the controller:

    def index
      #if no perspective, set to empty hash so solr skips
      params[:perspective] ||= []
      @search = Upload.search do
        with :approved, true
        with :perspective_id, params[:perspective]
        fulltext params[:tag]
        fulltext params[:search] do
          minimum_match 1
        end
        paginate page: params[:page], per_page: 30
      end
        @uploads = @search.results
        @query = params[:search]
    end