为什么会很糟糕?
为此使用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,这是一个很大的优势,因为它更清楚地表达了你的意图。