Sunspot / Solr / Rails: Model Associations are not

2019-03-21 03:31发布

问题:

I have a Fieldnote model in my app, which has_many :activities attached to it through a table called :fieldnote_activities. I then define a searchable index this way:

searchable :auto_index => true, :auto_remove => true do
  integer :id
  integer :user_id, :references => User

  integer :activity_ids, :multiple => true do
    activities.map(&:id)
  end

  text :observations
 end

And then I have a Search model to store / update searches. The search model thus also has its own associations with activities. I then perform my searches like this:

@search = Search.find(params[:id])
@query  = Fieldnote.search do |query|
  query.keywords  @search.terms

  if @search.activities.map(&:id).empty? == false
    query.with    :activity_ids, @search.activities.map(&:id)
  end

end
@fieldnotes = @query.results

Now this all works GREAT. The problem is that if I change which activities that are associated with a fieldnote, the search results do not change because it appears the indices for that fieldnote do not change. I was under the impression that the :auto_index => true and :auto_remove => true flags when I define the searchable index would keep track of new associations (or deleted associations), but this appears not to be the case. How do I fix this?

回答1:

You're right that :auto_index and :auto_remove don't apply to associated objects, just the searchable object they are specified on.

When denormalizing, you should use after_save hooks on the associated objects to trigger a reindex where necessary. In this case, you want changes to the Activity model and the FieldnoteActivity join model to trigger a reindex of their associated Fieldnote objects when saved or destroyed.

class Fieldnote
  has_many :fieldnote_activities
  has_many :activities, :through => :fieldnote_activities

  searchable do
    # index denormalized data from activities
  end
end

class FieldnoteActivity
  has_many :fieldnotes
  has_many :activities

  after_save :reindex_fieldnotes
  before_destroy :reindex_fieldnotes

  def reindex_fieldnotes
    Sunspot.index(fieldnotes)
  end
end

class Activity
  has_many :fieldnote_activities
  has_many :fieldnotes, :through => :fieldnote_activities

  after_save :reindex_fieldnotes
  before_destroy :reindex_fieldnotes

  def reindex_fieldnotes
    Sunspot.index(fieldnotes)
  end
end