diff --git a/lib/rails/observers/active_model/disabled_observers_registry.rb b/lib/rails/observers/active_model/disabled_observers_registry.rb new file mode 100644 index 0000000..f69cb5c --- /dev/null +++ b/lib/rails/observers/active_model/disabled_observers_registry.rb @@ -0,0 +1,13 @@ +module ActiveModel + class DisabledObserversRegistry + extend ActiveSupport::PerThreadRegistry + + attr_accessor :disabled_observers_per_class + attr_accessor :disabled_observers_stacks_per_class + + def initialize + @disabled_observers_per_class = {} + @disabled_observers_stacks_per_class = {} + end + end +end \ No newline at end of file diff --git a/lib/rails/observers/active_model/observer_array.rb b/lib/rails/observers/active_model/observer_array.rb index 77bc0f7..e9aa826 100644 --- a/lib/rails/observers/active_model/observer_array.rb +++ b/lib/rails/observers/active_model/observer_array.rb @@ -73,7 +73,11 @@ def enable(*observers, &block) protected def disabled_observers #:nodoc: - @disabled_observers ||= Set.new + DisabledObserversRegistry.disabled_observers_per_class[model_class] ||= Set.new + end + + def disabled_observers= observers #:nodoc: + DisabledObserversRegistry.disabled_observers_per_class[model_class] = observers end def observer_class_for(observer) #:nodoc: @@ -95,11 +99,11 @@ def start_transaction #:nodoc: end def disabled_observer_stack #:nodoc: - @disabled_observer_stack ||= [] + DisabledObserversRegistry.disabled_observers_stacks_per_class[model_class] ||= [] end def end_transaction #:nodoc: - @disabled_observers = disabled_observer_stack.pop + self.disabled_observers = disabled_observer_stack.pop each_subclass_array do |array| array.end_transaction end diff --git a/lib/rails/observers/active_model/observing.rb b/lib/rails/observers/active_model/observing.rb index 3f01a90..228cc08 100644 --- a/lib/rails/observers/active_model/observing.rb +++ b/lib/rails/observers/active_model/observing.rb @@ -1,4 +1,5 @@ require 'singleton' +require 'rails/observers/active_model/disabled_observers_registry' require 'rails/observers/active_model/observer_array' require 'active_support/core_ext/module/aliasing' require 'active_support/core_ext/module/remove_method' diff --git a/test/observer_array_test.rb b/test/observer_array_test.rb index 16fdf53..d103103 100644 --- a/test/observer_array_test.rb +++ b/test/observer_array_test.rb @@ -109,7 +109,6 @@ def assert_observer_not_notified(model_class, observer_class) test "can disable observers on individual models without affecting those observers on other models" do Widget.observers.disable :all - assert_observer_not_notified Widget, WidgetObserver assert_observer_notified Budget, BudgetObserver assert_observer_not_notified Widget, AuditTrail @@ -162,6 +161,13 @@ def assert_observer_not_notified(model_class, observer_class) assert_observer_notified Budget, AuditTrail end + test "can enable observer without side effects on other threads" do + Thread.new do + Widget.observers.disable :audit_trail + end.join() + assert_observer_notified Widget, AuditTrail + end + test "raises an appropriate error when a developer accidentally enables or disables the wrong class (i.e. Widget instead of WidgetObserver)" do assert_raise ArgumentError do ORM.observers.enable :widget