所有模型的ActiveRecord全局回调函数

7

我在我的RoR应用程序中有约40个模型。我想为所有模型设置一个after_save回调函数。一种方法是将其添加到所有模型中。由于此回调具有相同的要运行的代码,是否有一种方法可以全局定义它一次,以便它被调用所有模型。

我尝试过这个方法但没有成功:

class ActiveRecord::Base

  after_save :do_something

  def do_something
    # .... 
  end
end

如果我在单个模型中执行此代码,则相同的代码可以正常工作。

谢谢, Imran

5个回答

9
您应该使用观察者来实现这个功能:
class AuditObserver < ActiveRecord::Observer      

  observe ActiveRecord::Base.send(:subclasses)

  def after_save(record)
    AuditTrail.new(record, "UPDATED")
  end
end

为了激活一个观察者,您需要在config/application.rb文件中的config.active_record.observers配置设置中列出它。
config.active_record.observers = :audit_observer

注意

Rails 4中,观察者特性已从核心功能中删除。请使用https://github.com/rails/rails-observers gem。


太好了,谢谢!那么我需要将所有的模型添加到“observe”中,对吗?我希望有一种动态获取模型列表并将其传递给“observe”的方法?再次感谢。 - Saim
更新了我的答案,请看一下。 - Harish Shetty
1
很酷。我认为我们需要在“observe”之前添加这行代码,以确保所有模型都被加载:Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }如果我有错误,请纠正我,或者如果有更好的方法来确保所有模型都被加载。 - Saim
有没有Rails 4的替代品,因为这段代码在Rails 4中无法工作,是的,我已经添加了Observer gem。 - Grey
这个解决方案对我不起作用,我使用的是Rails 4和rails-observers 0.1.2。但我发现你可以只使用observe ActiveRecord::Base,它会在子类定义时观察它们(无需急切加载或检查子类或后代)。 - Anthony Smith
显示剩余2条评论

4

我可能有点晚,但如果还有人在使用Rails 3并找到这个问题,那么这个回答可能会有所帮助。

当观察者加载时,一些模型可能尚未加载。文档中说,您可以覆盖observed_classes,这样就可以动态获取活动记录的子类。

class AuditObserver < ActiveRecord::Observer
  def self.observed_classes                 
    ActiveRecord::Base.send(:subclasses)    
  end
end

这真的很酷,但我建议使用ActiveRecord :: Base.descendants来避免私有方法调用。 - ludwigschubert

1
这对我来说似乎管用:

ActiveRecord::Base.after_save do
   ...
end

我没有看到任何问题吗?


1

根据 @harish 的回答以及这篇回答 (https://dev59.com/jHRB5IYBdhLWcg3wxZ_Y#10712838):

class AuditObserver < ActiveRecord::Observer
    Rails.application.eager_load!
    observe ActiveRecord::Base.descendants

    def after_save(record)
        ...
    end
end

0

在2.3.8中,这对我来说实际上运作得非常好:

class AudiObserver < ActiveRecord::Observer
  observe :'ActiveRecord::Base'
  #
  # observe methods...
  #
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接