John Gibbons
John Gibbons

Reputation: 322

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.

Upvotes: 2

Views: 724

Answers (3)

Yunwei.W
Yunwei.W

Reputation: 1599

You don't have to write those extra coding actually. Just do it like this:

searchable do
  #...
  string :perspective
  #...
end

#while searching
with :perspective, 'above'

Upvotes: 0

John Gibbons
John Gibbons

Reputation: 322

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

Upvotes: 2

Dr.Strangelove
Dr.Strangelove

Reputation: 1495

Rails enums are quite a dark magic. Remember it's all integers in the database.

I'm betting your params[:perspective] is a string(like 'front') and not an underlying integer. Calling Model.perspectives[:front] on the other hand will return proper integer value. Try converting it to underlying value using

Model.perspectives[params[:perspective]]

before passing to search method.

More info here: rails docs

Upvotes: 0

Related Questions