2

我有一个模型,当它处于特定状态时,需要一些额外的数据然后发送邮件。

为此,我有一个验证前回调说

“我处于需要数据的状态,我需要更多数据吗?不?然后我会改变我的状态并发送邮件”。

此状态每晚由 cron rake 触发,有时不需要数据,因此应尽快发送邮件。稍后当收集到数据时,将触发回调,邮件将按原样发送。

我已阅读并被告知邮件只能从控制器发送。但这意味着我需要在我的控制器和我的 rake 中发送邮件。

为什么从回调发送邮件“不好”?

从一个地方触发邮件到两个不同的地方不是一个坏主意吗?

4

1 回答 1

6

为什么会很糟糕?

为此使用ActiveRecord::Observer。这是一个完美的用例,因为邮件逻辑可能既不属于您的模型,也不属于控制器。

class WelcomeEmailObserver < ActiveRecord::Observer
  observe :user

  def after_create(user)
    if user.purchased_membership?
      GreetingMailer.welcome_and_thanks_email(user).deliver
    else
      GreetingMailer.welcome_email(user).deliver
    end
  end
end

# app/models/user.rb
class User
end

# config/application.rb
class Application < Rails::Application
  config.active_record.observers = :welcome_email_observer
end

从这里偷来的例子。

我还建议您让观察者保持无状态,因为否则很难调试它们。仅将它们用于与第三方 API、电子邮件或其他与您的应用程序不太相关的东西的回调。

我建议你使用no-peeping-toms来测试它们。不要将观察者测试与模型测试隔离开来——这没有多大意义,但一定要在有观察者和没有观察者的情况下测试模型。使用此辅助 gem,您可以定位您喜欢的观察者并将其打开或关闭。

对观察者执行单一职责原则,不要将它们与模型耦合。让观察者远离持久性逻辑。使用模型回调来解决与持久性相关的问题。

另外,我想警告你在使用像 Sidekiq 这样的东西时要小心观察者。它有时比 ActiveRecord 回调更快,因此您应该使用after_commit回调来避免冲突。

备择方案

ActiveRecord::Observers 将在 Rails 4.0 中被弃用,因为它们被提取到 gem 中。不过,您仍然可以使用它们,但似乎 Rails 核心团队强制将所有内容提取到具有单一职责的类中。选择使用什么取决于您的口味。

观察者使一切变得不那么明确,并且肯定会更复杂地测试。如果您知道自己在做什么,他们仍然可以成为优秀的 OO 公民。

使用普通的旧红宝石对象对我来说似乎更像 DCI,这是一个很大的优势,因为它更清楚地表达了你的意图。

于 2013-06-24T10:18:08.303 回答