ActionMailer最佳实践:在模型或控制器中调用方法?

25
发送电子邮件通常称为模型操作,但电子邮件本身是视图操作。我正在寻找您认为应该问自己什么问题以确定在哪里调用动作邮件程序方法的思考方式。
我见过/使用过以下几种情况:
  • 在模型方法中-相关但分离的关注点耦合度高?
  • 在模型的回调函数中(例如after_save)-就我目前水平而言,这是最好的分离。
  • 在控制器操作中-感觉不对,但是否有情况下这是组织代码的最聪明方式?
如果我想要学会编程,我需要像程序员一样思考,因此学习如何考虑特定的编程解决方案比我独自在隔离中进行数月编码更有价值。谢谢!
4个回答

17

回答晚了,但我想对这个主题进行合理化说明:

通常,在Web应用程序中,您希望发送电子邮件,无论是直接响应客户还是作为后台任务,如果我们谈论的是类似于通讯/通知邮件的东西。

该模型基本上是数据存储映射器。其逻辑应该封装数据处理/与数据存储处理的通信。因此,插入与之不相关的逻辑有点棘手,并且在大多数情况下是错误的。让我们以一个例子为例:用户注册帐户并应收到确认电子邮件。在这种情况下,可以说,确认电子邮件是创建新帐户的直接影响。现在,尝试在控制台中创建用户而不是在Web应用程序中这样做。在这种情况下触发回调听起来很奇怪,对吧?因此,回调选项被取消了。我们是否仍然应该在模型中编写该方法?好吧,如果它是用户操作/输入的直接结果,则应保留在该工作流程中。我会在成功创建用户后将其直接编写在控制器中。在模型中复制此逻辑以在控制器中调用它实际上增加了不必要的模块化和Active Record模型从Action Mailer的依赖性。尝试考虑在许多应用程序上共享该模型,其中一些不希望使用Action Mailer。出于上述原因,我认为邮件调用应该出现在它们有意义的地方,而通常模型不是那个地方。请给我举几个它确实适用的例子。


1
稍后再评论,但这里有一个例子,在模型中可能会有意义:当状态更改后触发电子邮件。例如,如果用户被锁定(例如将“状态”更改为“已锁定”),则应该收到电子邮件,无论它是如何被锁定的。你觉得呢? - Gerry

4

嗯,这取决于具体情况。

我曾经使用过所有这些选项,你关于“为什么我要把它放在哪里”的观点很好。

如果我想让某个模型以特定的方式更新时每次发生一些事情,那么我会把它放在模型中。甚至可以把它放在模型的回调函数中。

有时候你只是要发送一份报告;没有任何更新。在这种情况下,我通常会有一个资源,其中包括一个index操作来发送报告。

如果邮件发送器与正在更改的模型没有实际关系,我可以考虑把它放在回调函数中。但我不经常这样做。我更可能仍然将其封装在模型中。我做过这样的事,但并不经常。


2

我知道已经过了一段时间,但最佳实践永不过时,对吗? :)

电子邮件在定义上是异步通信(除了确认邮件,但即使是这种情况,在确认之前也应该留出一定的延迟,是最佳实践)。

因此,在我看来,发送邮件最合理的方式是:

  • 使用后台操作(使用 Sidekiqdelayed_job
  • 使用回调方法:“嘿,此操作已成功完成,也许我们现在可以告诉世界?”

Rails 中的问题是没有太多回调(例如 JavaScript):我个人认为像下面这样的代码很糟糕:

after_save :callback

def callback
  if test_that_is_true_once_in_the_objects_life
    Mailer.send_email()
  end
end

所以,如果你真的想要像程序员一样思考,那么你需要在你的应用中设置一些定制的回调系统。
例如:
def run_with_callback(action, callback_name)
  if send(action)
    delay.send(callback_name)
  end
end

甚至在您的应用程序中创建事件系统也是一个不错的解决方案。

但最终,这些解决方案所需的时间成本相当高,因此人们最终会在操作后将其内联编写。

def activate
  [...]
  user.save
  Mailer.send_mail
  respond_to 
  [...]
end

回调函数是同步编程中最接近异步编程的方式,可以在ModelController中随处调用邮件发送器。


0

控制器是邮件发送器的好地方,原因如下:

  • 与模型无关的电子邮件。
  • 如果您的电子邮件依赖于多个不知道彼此的模型。
  • 将模型提取到API中不应意味着需要重新实现邮件发送器。
  • 邮件发送器内容由请求变量确定,您不想将其传递给模型。
  • 如果您的业务模型需要大量不同的电子邮件,则模型回调可能会堆叠。
  • 如果电子邮件不依赖于模型计算结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接