Search code examples
thinking-sphinxruby-on-rails-4.2

Thinking Sphinx Has Many Through Rails


Can you please help me in thinking sphinx?

Relationship:

Continent has_many :countries has_many :country_reports, through: :countries, :class_name => "Report" has_many :publishers, through: :country_reports

Expected Output:

I want to find Continent.first.publishers

Please tell me how to write this in thinking sphinx rails


Solution

  • As I answered on the Thinking Sphinx Google group:

    Because you’re searching on publishers, it’s the Publisher index you’ll need to modify to get this to work. I’m presuming a publisher belongs_to :country_report, country report belongs_to :country, and country belongs_to :continent.

    If you’re using SQL-backed indices (using the :with => :active_record option), then you’ll want the following in your Publisher index:

    has country_report.country.continent_id, :as => :continent_id
    

    If you’re using real-time indices (:with => :real_time), then it’s the same, but you must specify the type as well:

    has country_report.country.continent_id, :as => :continent_id, :type => :integer
    

    However, if there’s a has_many or has_and_belongs_to_many instead of belongs_to in that chain of associations from publisher to continent, then it’s a little more complicated. Also, in this case, it might be possible to have more than one continent for a publisher, so we’re dealing with multiple values here.

    For SQL-backed indices, a minor change, alter the associations chain:

    has country_reports.country.continent_id, :as => :continent_ids
    

    But with a real-time index, it’s better to have a method on the Publisher model that returns the necessary value or values, and then use that in the index:

    # in app/models/publisher.rb
    def continent_ids
      country_reports.collect(&:country).collect(&:continent_id)
    end
    
    # in app/indices/publisher_index.rb
    has continent_ids, :type => :integer, :multi => true
    

    And then, once you’ve rebuilt your index, you can search as follows (with the attribute being plural if appropriate):

    Publisher.search “foo”, :with => {:continent_id => continent.id}
    

    This may work as well (the multiple levels of associations may confuse things though):

    continent.publishers.search “foo”