aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/observer.rb
diff options
context:
space:
mode:
authorMislav Marohnić <mislav.marohnic@gmail.com>2010-04-16 19:37:12 +0200
committerJeremy Kemper <jeremy@bitsweat.net>2010-04-16 13:12:53 -0700
commit2161b8745a22379356b466a60b9aa763c0593f9b (patch)
treecb5a3df164f14d85d9916b97d4d4de0c3b609b31 /activerecord/lib/active_record/observer.rb
parentc2ca73c9ee5fc3dadf69cf565bd5e2bb30c82c50 (diff)
downloadrails-2161b8745a22379356b466a60b9aa763c0593f9b.tar.gz
rails-2161b8745a22379356b466a60b9aa763c0593f9b.tar.bz2
rails-2161b8745a22379356b466a60b9aa763c0593f9b.zip
improve how ActiveRecord::Observer defines callbacks on observed models
Instead of using a single `notify_observers` call for every callback type, each observer now registers a unique callback for itself. Example: before_save :_notify_user_observer_for_before_save def _notify_user_observer_for_before_save observer.update(:before_save, self) end Benefit: "before" callbacks halt when `observer.update` returns false. This way, ActiveRecord observers can prevent records from saving. [#4087 state:committed] Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
Diffstat (limited to 'activerecord/lib/active_record/observer.rb')
-rw-r--r--activerecord/lib/active_record/observer.rb26
1 files changed, 19 insertions, 7 deletions
diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb
index 0fbb1f0261..ed0f039597 100644
--- a/activerecord/lib/active_record/observer.rb
+++ b/activerecord/lib/active_record/observer.rb
@@ -96,7 +96,8 @@ module ActiveRecord
end
def self.method_added(method)
- self.observed_methods += [method] if ActiveRecord::Callbacks::CALLBACKS.include?(method.to_sym)
+ method = method.to_sym
+ observed_methods << method if ActiveRecord::Callbacks::CALLBACKS.include?(method)
end
protected
@@ -104,16 +105,27 @@ module ActiveRecord
observed_classes.sum([]) { |klass| klass.send(:subclasses) }
end
+ def observe_callbacks?
+ self.class.observed_methods.any?
+ end
+
def add_observer!(klass)
super
+ define_callbacks klass if observe_callbacks?
+ end
+
+ def define_callbacks(klass)
+ existing_methods = klass.instance_methods.map(&:to_sym)
+ observer = self
+ observer_name = observer.class.name.underscore.gsub('/', '__')
- # Check if a notifier callback was already added to the given class. If
- # it was not, add it.
self.class.observed_methods.each do |method|
- callback = :"_notify_observers_for_#{method}"
- if (klass.instance_methods & [callback, callback.to_s]).empty?
- klass.class_eval "def #{callback}; notify_observers(:#{method}); end"
- klass.send(method, callback)
+ callback = :"_notify_#{observer_name}_for_#{method}"
+ unless existing_methods.include? callback
+ klass.send(:define_method, callback) do # def _notify_user_observer_for_before_save
+ observer.update(method, self) # observer.update(:before_save, self)
+ end # end
+ klass.send(method, callback) # before_save :_notify_user_observer_for_before_save
end
end
end