Joe Saunders
Joe Saunders

Reputation: 798

How do I limit Tire/ElasticSearch results by association?

I have a collection of posts that are within categories and subcategories using a belongs_to association. Additionally, the posts have a belongs_to relationship with my state and city models.

I am limiting the display of the posts at the controller to those belonging to the respective location (i.e. city or state) by using a request.subdomain check on the subdomain in the URL. This works perfectly for everything except search using Tire/ElasticSearch.

For some reason I can't get Tire to limit search results to the posts belonging to a specific location. I've tried getting the subdomain into the model using a cater_accessor :request_subdomain in the model and adding a before_filter in the controller where @city_or_state is location associated with the subdomain.

 def set_request_subdomain
   Post.request_subdomain = @city_or_state if !@city_or_state.nil?
 end

Here's my model:

  def self.search(params)
tire.search(load: true, page: params[:page], per_page: 10) do
  query { string params[:query], default_operator: "AND" } if params[:query].present?
  filter :terms, :published => [true]
  filter :terms, :request_subdomain => [:city_subdomain || :state_subdomain] 
end
end

def to_indexed_json
  to_json(methods: [:city_name, :city_subdomain, :state_name, :state_subdomain])
end

def city_name
  self.city.name
end

def city_subdomain
  city.subdomain.titleize
end

def state_name
  self.state.name
end

def state_subdomain
  state.subdomain.titleize
end

I need the search to limit results by the location (i.e. subdomain).

What am I missing here?

UPDATE: I have followed this railscast and been able to get Facets to work... I'm thinking maybe I can limit the items searched based on a Facet (i.e. without a user selecting a Facet as in the railscast), but I haven't been able to get that working.

Any ideas?

Upvotes: 2

Views: 1106

Answers (2)

Frederick Cheung
Frederick Cheung

Reputation: 84114

This

filter :terms, :request_subdomain => [:city_subdomain || :state_subdomain] 

is back to front - the left hand side of the hashrocket should be a property of your tire index, and the right hand side that value it should match. Secondly, this is just plain ruby so

[:city_subdomain || :state_subdomain] 

evaluates to just :city_subdomain, the 'or' doesn't magically make its way into the query logic

You want instead to say that either the :city_subdomain matches a certain value or the state_subdomain matches. You could do that with something like this, assuming that subdomain was a local variable or argument to your search method (far preferable to a class level variable)

filter :or, [
               {:term => {:city_subdomain => subdomain}},
               {:term => {:state_subdomain => subdomain}}
            ] 

Upvotes: 1

jeremywoertink
jeremywoertink

Reputation: 2341

If you're looking for the number of results to be limited, you can always run some ruby inside of your search block, and use the size and from methods.

search = Tire.search(Location.index_name) do |s|
    s.query do |q|
        q.string "las vegas"
    end
    # Best used for pagination
    s.size 25 # limit 25 results
    s.from 0 # start at the beginning.
end

I'm not sure exactly what you'd need, but you could always do something like

if something.nil?
    s.size 0
else
    s.size 25
end

That would be changing the limit based on some condition.

Upvotes: 0

Related Questions