ruby-on-rails - Rails Observers - 何时在 Rails 中使用观察者,何时不使用

标签 ruby-on-rails ruby-on-rails-3

在我目前正在工作的应用程序中,我看到了很多观察者。当我更改代码、添加新功能时,这确实给我带来了很多麻烦,因为这些观察者会导致大量副作用。

我想知道需要观察者的场合,以及人们在被诱惑掉入观察者陷阱时的经验或个人经验。

需要您的宝贵经验、 war 故事和思想。请大声喊出来!

最佳答案

我觉得观察者获得不好的评价主要是因为人们将它们与 ActiveRecord 生命周期回调混为一谈。我确实同意很多流行的观点,即生命周期回调很容易被误用,让自己陷入困境,但我个人是观察者的忠实粉丝,因为它们将不是特定模型核心职责的模型类排除在外。这里有一个提示:Rails 的观察者部分受到了面向方面编程的启发——它们是关于横切关注点的。如果您将业务逻辑放在与他们正在观察的模型紧密耦合的观察者中,那么您在 IMO 上做错了。

它们非常适合让模型类保持困惑,例如缓存过期(清扫器)、各种通知、事件流更新、启动后台作业以跟踪自定义分析事件、热缓存等。

我坚决不同意 BlueFish 关于观察者难以正确进行单元测试的观点。这正是将它们与生命周期回调区分开来的最大点:您可以孤立地测试观察者,这样做可以防止您陷入 BlueFish 所指的许多状态和顺序繁重的设计陷阱(我再次认为这更常见)生命周期回调为真)。

这是我的处方:

  • 默认情况下禁用测试套件中的所有观察者 .它们不应该使您的模型测试复杂化,因为无论如何它们都应该有不同的关注点。您不需要对观察者实际触发进行单元测试,因为 ActiveRecord 的测试套件会这样做,并且您的集成测试将涵盖它。使用 ActiveRecord::Base.observers.enable 的块形式如果您真的相信有充分的理由为单元测试的一小部分启用观察者,但这可能是误用或设计问题的指标。
  • 仅为您的集成测试启用观察者 .集成测试当然应该是全栈的,你应该像其他所有事情一样验证它们中的观察者行为。
  • 单独对观察者类进行单元测试 (直接调用 after_create 之类的方法)。如果观察者不是其被观察模型的业务逻辑的一部分,它可能不会过多依赖模型实例的状态细节,并且不需要太多的测试设置。如果您有理由相信您的集成测试涵盖了您最关心的内容,那么您通常可以在此处模拟协作者。

  • 这是我的标准样板 spec/support/observers.rb对于使用 RSpec 的应用程序:

    RSpec.configure do |config|
      # Assure we're testing models in isolation from Observer behavior. Enable
      # them explicitly in a block if you need to integrate against an Observer --
      # see the documentation for {ActiveModel::ObserverArray}.
      config.before do
        ActiveRecord::Base.observers.disable :all
      end
    
      # Integration tests are full-stack, lack of isolation is by design.
      config.before(type: :feature) do
        ActiveRecord::Base.observers.enable :all
      end
    end
    

    here is a real-world example我希望这说明了使用观察者的一个很好的例子,并且没有痛苦地测试它。

    关于ruby-on-rails - Rails Observers - 何时在 Rails 中使用观察者,何时不使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4866509/

    相关文章:

    ruby-on-rails - 如何强制execjs使用Node.js?

    javascript - Rails 3 HTML 5/javascript 免费绘图推荐

    ruby-on-rails - Rails simple_form 记住密码输入

    ruby-on-rails - 在 Rails ActiveAdmin gem 中修改 BaseController

    javascript - 将 javascript 变量传递给 Rails Controller

    ruby-on-rails - 如何在 Fabrication 的计数参数中使用 transient 属性?

    ruby-on-rails - Rails 3. before_destroy 验证以防止删除父记录

    ruby-on-rails - Rails - 从一个模型在另一个模型中创建实例

    ruby-on-rails - 如何在 Active Admin 中为 Edit 和 New 设置页面标题?

    ruby-on-rails-3 - 如何在 Rails 控制台中访问 Rails 3 引擎模型