我有一个模型,当它处于特定状态时,需要一些额外的数据,然后发送邮件。
为此,我有一个前验证回调,说
“我处于这种我需要数据的状态,我需要更多数据吗?不是吗?那么我将改变我的状态并发送邮件”。
这种状态是每晚由cron rake触发的,有时候不需要数据,所以它应该尽快发送邮件。稍后收集数据时,将触发回调并且邮件将继续运行。
我已阅读并被告知邮件应仅从控制器发送。但这里的意思是我需要在我的控制器和我的佣金中发送邮件。
为什么从回调中发送邮件“不好”?
从一个地方出发将邮件发送到两个不同的地方不是一个坏主意吗?
答案 0 :(得分: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
来自here的示例。
我还建议您让观察者无国籍,否则很难调试它们。仅将它们用于与第三方API,电子邮件或其他与您的应用程序无关的内容的回调。
我建议您使用no-peeping-toms进行测试。不要将观察者测试与模型测试隔离开来 - 这没有多大意义,但一定要在有和没有观察者的情况下测试模型。使用此辅助宝石,您可以定位您喜欢的观察者并打开或关闭它。
对观察者实施单一责任原则,不要将它们与模型联系起来。让持久性逻辑远离观察者。使用模型回调来解决与持久性相关的问题。
另外,我想警告你在使用像Sidekiq这样的东西时要小心观察者。它有时比ActiveRecord回调更快,因此您应该使用after_commit
回调来避免冲突。
ActiveRecord :: Observers将在Rails 4.0中弃用,因为它们被提取到gem中。但是,您仍然可以使用它们,但似乎Rails核心团队强制将所有内容提取到单一职责的类中。选择使用方法取决于您的口味。
观察者会使一切变得不那么明确,而且确定测试更加复杂。如果你知道自己在做什么,他们仍然可以成为优秀的OO公民。
使用普通的旧红宝石物体对我来说似乎更像DCI,这是一个很大的优点,因为它更清楚地表达了你的意图。