acts_as_ferret does not handle transaction aborts properly. If a model
is modified but something latter causes the transaction it was wrapped
in to abort, the ferret index will not revert to the original record
data. I have included a klunky patch to defer modifying the ferret
index until after the current transaction commits. It would seem
prudent to resolve this issue, though I don’t think I have an ideal
solution.
I have an acts_as_ferret model that has indexed properties that are
derived from other models that it is associated with. As a side effect
this patch ensures that if I wrap modifications to the model and the
associated models in a transaction all the modifications to the
associated models make it into the ferret index.
Thoughts?
Index: lib/acts_as_ferret.rb
— lib/acts_as_ferret.rb (revision 59)
+++ lib/acts_as_ferret.rb (working copy)
@@ -496,7 +496,8 @@
module InstanceMethods
attr_reader :reindex
-
@ferret_reindex = true
-
@ferret_reindex = false -
@defer_for_transaction = false def ferret_before_update @ferret_reindex = true
@@ -505,9 +506,13 @@
# add to index
def ferret_create
-
logger.debug "ferret_create/update: #{self.class.name} :
#{self.id}"
-
self.class.ferret_index << self.to_doc if @ferret_reindex -
@ferret_reindex = true
-
unless @defer_for_transaction -
logger.debug "ferret_create/update: #{self.class.name} :
#{self.id}"
-
self.class.ferret_index << self.to_doc if @ferret_reindex -
@ferret_reindex = true -
else -
logger.debug "deferred ferret_create/update:
#{self.class.name} : #{self.id}"
-
end true end alias :ferret_update :ferret_create
@@ -522,6 +527,21 @@
end
true
end
+
-
def at_start_transaction(name = nil) -
@defer_for_transaction = true -
end -
def at_abort_transaction(name = nil) -
@defer_for_transaction = false -
@ferret_reindex = false -
end -
def at_commit_transaction(name = nil) -
@defer_for_transaction = false -
ferret_create -
@ferret_reindex = false -
end # convert instance to ferret document def to_doc
@@ -786,4 +806,28 @@
end
end
+module Transaction
- module Simple
- alias :start_transaction_object :start_transaction
- alias :abort_transaction_object :abort_transaction
- alias :commit_transaction_object :commit_transaction
- def start_transaction(name = nil)
-
at_start_transaction(name) if respond_to?(:at_start_transaction) -
start_transaction_object(name) - end
- def abort_transaction(name = nil)
-
at_abort_transaction(name) if respond_to?(:at_abort_transaction) -
abort_transaction_object(name) - end
- def commit_transaction(name = nil)
-
at_commit_transaction(name) if
respond_to?(:at_commit_transaction)
-
commit_transaction_object(name) - end
- end
+end