我应该从模型回调或控制器发送邮件吗?

时间:2013-06-24 10:06:44

标签: ruby-on-rails model-view-controller callback

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

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

“我处于这种我需要数据的状态,我需要更多数据吗?不是吗?那么我将改变我的状态并发送邮件”。

这种状态是每晚由cron rake触发的,有时候不需要数据,所以它应该尽快发送邮件。稍后收集数据时,将触发回调并且邮件将继续运行。

我已阅读并被告知邮件应仅从控制器发送。但这里的意思是我需要在我的控制器和我的佣金中发送邮件。

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

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

1 个答案:

答案 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,这是一个很大的优点,因为它更清楚地表达了你的意图。