mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
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>
This commit is contained in:
parent
c2ca73c9ee
commit
2161b8745a
2 changed files with 24 additions and 7 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
|
||||||
|
|
||||||
|
* Observers can prevent records from saving by returning false, just like before_save and friends. #4087 [Mislav Marohnić]
|
||||||
|
|
||||||
|
|
||||||
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
|
*Rails 3.0.0 [beta 3] (April 13th, 2010)*
|
||||||
|
|
||||||
* Add Relation extensions. [Pratik Naik]
|
* Add Relation extensions. [Pratik Naik]
|
||||||
|
|
|
@ -96,7 +96,8 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.method_added(method)
|
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
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
@ -104,16 +105,27 @@ module ActiveRecord
|
||||||
observed_classes.sum([]) { |klass| klass.send(:subclasses) }
|
observed_classes.sum([]) { |klass| klass.send(:subclasses) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def observe_callbacks?
|
||||||
|
self.class.observed_methods.any?
|
||||||
|
end
|
||||||
|
|
||||||
def add_observer!(klass)
|
def add_observer!(klass)
|
||||||
super
|
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|
|
self.class.observed_methods.each do |method|
|
||||||
callback = :"_notify_observers_for_#{method}"
|
callback = :"_notify_#{observer_name}_for_#{method}"
|
||||||
if (klass.instance_methods & [callback, callback.to_s]).empty?
|
unless existing_methods.include? callback
|
||||||
klass.class_eval "def #{callback}; notify_observers(:#{method}); end"
|
klass.send(:define_method, callback) do # def _notify_user_observer_for_before_save
|
||||||
klass.send(method, callback)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue