Search code examples
ruby-on-railsrubysphinxthinking-sphinx

ThinkingSphinx - Search through has_many association


I have a relationship between two models, Idea and Iteration. Each idea can have many iterations. The models looks like this;

# idea.rb
has_many :iterations, dependent: :destroy

# I also use with: :real_time 
after_save ThinkingSphinx::RealTime.callback_for(:idea)

# iteration.rb
belongs_to :idea
after_save ThinkingSphinx::RealTime.callback_for(:idea, [:idea])

My indexes for Idea looks like this:

ThinkingSphinx::Index.define :idea, :with => :real_time do
  [...]
  indexes iterations.title, as: :iteration_titles
  indexes iterations.description, as: :iteration_descriptions
  has iterations.id, :as => :iteration_ids, type: :integer
  [...]
end

And I search like this:

@ideas = @user.ideas.search  ThinkingSphinx::Query.escape(params[:search]),
  :with => {:team_id => @teams.collect(&:id)},
  :page     => params[:page],
  :per_page => 10,
  :order    => 'created_at DESC'

Currently, searching for either Iteration title or description returns 0 hits. And I have performed:

rake ts:rebuild
rake ts:regenerate
rake ts:index

Have I missed something?


Solution

  • One of the differences between real-time indices and SQL-backed indices is that with SQL-backed indices, you refer to associations and columns in your index definition, but with real-time indices, you refer to methods.

    And while iterations is an instance method within an idea, title, description and id are not methods on the object returned by iterations.

    The easiest way to work through this has two parts. Firstly, add instance methods to Idea that return the data you want for the iteration-related fields and attributes:

    def iteration_titles
      iterations.collect(&:title).join(' ')
    end
    
    def iteration_descriptions
      iterations.collect(&:description).join(' ')
    end
    
    def iteration_ids
      iterations.collect &:id
    end
    

    And then use those methods in your index definition:

    indexes iteration_titles, iteration_descriptions
    has iteration_ids, :type => :integer, :multi => true
    

    And then, run rake ts:regenerate to get it all set up (ts:rebuild and ts:index have no meaning for real-time indices).