-
-
Save jumski/5314109 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Foo < ActiveRecord::Base | |
has_many :bars | |
belongs_to :baz | |
include IndexingHandler | |
indexed_associations :bars, :baz | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, noticed you forked this. I made a gem out of it here: https://github.com/paulnsorensen/lifesaver