Search code examples
ruby-on-rails-4thinking-sphinx

Rails 4 - Thinking Sphinx filter using field on related model


In my Rails 4 app I have models like:

'AgencyGroup'

has_many :group_agencies
has_many :agencies, :through => :group_agencies

Where I keep 'token' field

'Agency' model

  has_many :group_agencies
  has_many :agency_groups, :through => :group_agencies
  has_many :advertisements

'Advertisement' model

  belongs_to :agency

I use Thinking Sphinx and it works really greate but now I got new requirement to filter 'Advertisements' by AgencyGroup token fields.

Basically I need to find advertisment with some parameters but only for agencies that are in agency group with posted token.

if params[:search]
 @results = Advertisement.search Riddle::Query.escape(params[:search]), :star => true, :page => params[:page], :per_page => 6
end

To get results I run http query like this:

http://api.localhost.local:3000/v1/advertisements?token=JHW_tdXn5g-vQY1f_ZzLuw&search=Nissim

What I'm missing? How to use relation between models in TS?


Solution

  • I think the best approach here involves a few steps:

    Step 1: Add AgencyGroup IDs as an attribute in your Advertisement index. If you're using SQL-backed indices (:with => :active_record), it's a one-liner:

    has agency.group_agencies.agency_group.id, :as => :agency_group_ids
    

    If you're using real-time indices, then you'll want a method in Advertisement that returns all of those IDs:

    def agency_group_ids
      agency.agency_group_ids
    end
    

    And your attribute definition will look like this:

    has agency_group_ids, :type => :integer, :multi => true
    

    Step 2: Because you've changed your index structure, don't forget to rebuild your indices:

    # for SQL-backed indices:
    rake ts:rebuild
    # or, for real-time indices
    rake ts:regenerate
    

    Step 3: In your controller, find the agency group for the given token:

    agency_group = AgencyGroup.find_by :token => params[:token]
    

    Step 4: Finally, use that agency group's id in your search call:

    @results = Advertisement.search Riddle::Query.escape(params[:search]),
      :star     => true,
      :page     => params[:page],
      :per_page => 6,
      :with     => {:agency_group_ids => agency_group.id}