Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Simplifies observer implementation [#6065 state:resolved]

  • Loading branch information...
commit 61f2d52d8a95ca89ebcb107848890c07b014750c 1 parent 60744d2
Robert Pankowecki (Gavdi) authored tenderlove committed
View
30 activerecord/lib/active_record/observer.rb
@@ -89,51 +89,29 @@ module ActiveRecord
# singletons and that call instantiates and registers them.
#
class Observer < ActiveModel::Observer
- class_attribute :observed_methods
- self.observed_methods = [].freeze
def initialize
super
observed_descendants.each { |klass| add_observer!(klass) }
end
- def self.method_added(method)
- method = method.to_sym
-
- if ActiveRecord::Callbacks::CALLBACKS.include?(method)
- self.observed_methods += [method]
- self.observed_methods.freeze
- end
- end
-
protected
def observed_descendants
observed_classes.sum([]) { |klass| klass.descendants }
end
- def observe_callbacks?
- self.class.observed_methods.any?
- end
-
def add_observer!(klass)
super
- define_callbacks klass if observe_callbacks?
+ define_callbacks klass
end
def define_callbacks(klass)
- existing_methods = klass.instance_methods.map { |m| m.to_sym }
observer = self
- observer_name = observer.class.name.underscore.gsub('/', '__')
- self.class.observed_methods.each do |method|
- 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
+ ActiveRecord::Callbacks::CALLBACKS.each do |callback|
+ next unless respond_to?(callback)
+ klass.send(callback){|record| observer.send(callback, record)}
end
end
end
View
16 activerecord/test/cases/lifecycle_test.rb
@@ -9,10 +9,19 @@ class SpecialDeveloper < Developer; end
class SalaryChecker < ActiveRecord::Observer
observe :special_developer
+ attr_accessor :last_saved
def before_save(developer)
return developer.salary > 80000
end
+
+ module Implementation
+ def after_save(developer)
+ self.last_saved = developer
+ end
+ end
+ include Implementation
+
end
class TopicaAuditor < ActiveRecord::Observer
@@ -179,4 +188,11 @@ def test_invalid_observer
developer = SpecialDeveloper.new :name => 'Rookie', :salary => 50000
assert !developer.save, "allowed to save a developer with too low salary"
end
+
+ test "able to call methods defined with included module" do # https://rails.lighthouseapp.com/projects/8994/tickets/6065-activerecordobserver-is-not-aware-of-method-added-by-including-modules
+ SalaryChecker.instance # activate
+ developer = SpecialDeveloper.create! :name => 'Roger', :salary => 100000
+ assert_equal developer, SalaryChecker.instance.last_saved
+ end
+
end

4 comments on commit 61f2d52

@anandkumaragrawal

Any specific reason for removing the following methods
:observe_callbacks?, :observed_methods, :observed_methods=, :observed_methods?

Actually, I am using obj.observed_methods, which is failing in case of upgrading rails version, How to achieve this ??

Thanks
Anand

@steveklabnik
Collaborator

Observers were extracted to a gem for Rails 4, if you're using edge, then you need to do that.

@anandkumaragrawal

Thanks Steve,
Actually my mistake, I did not mention the version.
I am migrating my rails version from 3.0.1 to 3.0.19. So, still do i need to go for a gem

@steveklabnik
Collaborator

No, you don't need a gem on that version.

Please sign in to comment.
Something went wrong with that request. Please try again.