public
Last active

UPDATE: I have way better code that accomplishes this now at [https://github.com/paulnsorensen/lifesaver] Module to ease associated models that are indexed by tire. Use this to trigger reindexing instead of having to touch all the files.

  • Download Gist
foo.rb
Ruby
1 2 3 4 5 6 7 8 9
#
# Please go to https://github.com/paulnsorensen/lifesaver
#
class Foo < ActiveRecord::Base
has_many :bars
belongs_to :baz
include IndexingHandler
indexed_associations :bars, :baz
end
index_helper.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
module IndexingHandler
extend ActiveSupport::Concern
 
included do
@indexing_suppressed = true if Rails.env == 'test'
after_save :enqueue_update_index, unless: :suppress_index?
after_destroy :enqueue_remove_index, unless: :suppress_index?
after_save :update_associated_indexes, unless: :suppress_index?
before_destroy :update_associated_indexes_for_destroy, unless: :suppress_index?
end
 
module ClassMethods
def indexed_associations(*args)
@association_names ||= []
if args.empty?
return @association_names
else
if args.last.is_a?(Hash)
@indexed_associations_options = args.last.clone
args.delete_at(args.size - 1)
end
@association_names << args.pop while !args.empty?
end
@association_names
end
 
def indexed_associations_options
@indexed_associations_options
end
end
 
def suppress_index?
@indexing_suppressed ? true : false
end
 
def suppress_index
@indexing_suppressed = true
end
 
def unsuppress_index
@indexing_suppressed = false
end
 
# if not using resque or any other asynchronous processing
# you could just use tire.update_index
def enqueue_update_index
if respond_to?(:tire)
Resque.enqueue(Indexer, self.class.name.underscore.to_sym, self.id, :update)
end
end
def enqueue_remove_index
if respond_to?(:tire)
Resque.enqueue(Indexer, self.class.name.underscore.to_sym, self.id, :remove)
end
end
 
def update_associated_indexes(for_destroy = false)
@triggered_save = true # this was the model that triggered the save
visited_models = {}
visited_models[self] = true
indexed_models = get_associated_indexed_models(visited_models, for_destroy)
indexed_models.each do |m|
unless m == self # we've already reindexed
m.enqueue_update_index
end
end
@triggered_save = false # reset method
true # so callbacks still run
end
 
def update_associated_indexes_for_destroy
update_associated_indexes(true)
end
 
def get_associated_indexed_models(visited_models, for_destroy = false)
indexed_models = Set.new
opts = self.class.indexed_associations_options
skip_associations = {}
if opts && opts[:only_on_save] && !@triggered_save
return indexed_models
end
if for_destroy
self.class.reflect_on_all_associations.each do |assoc|
if assoc.options[:dependent].present? # we will be touching it and triggering reindexing elsewhere
skip_associations[assoc.name.to_sym] = assoc
end
end
end
self.class.indexed_associations.each do |assoc|
next if skip_associations[assoc]
 
# TODO: find way to eliminate calling recursive relationships (if possible)
target = self.send(assoc)
unless target.nil?
if target.respond_to?(:each)
target.each do |t|
unless visited_models[t]
visited_models[t] = true
if t.respond_to?(:tire)
indexed_models << t
end
indexed_models |= t.get_associated_indexed_models(visited_models)
end
end
else # must be a single association then
unless visited_models[target]
visited_models[target] = true
if target.respond_to?(:tire)
indexed_models << target
end
indexed_models |= target.get_associated_indexed_models(visited_models)
end
end
end
end
indexed_models
end
 
end
indexer.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# Resque job for indexing
class Indexer
@queue = :indexing_queue
def self.perform(class_name, id, action)
klass = class_name.to_s.classify.constantize
case action.to_sym
when :update
if klass.exists?(id)
klass.find(id).update_index
end
when :remove
klass.index.remove({document: klass.document_type, id: id})
end
end
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.