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

发布于 2024-07-13 01:50:05 字数 327 浏览 11 评论 0原文

发送电子邮件通常是在对模型执行操作后调用的,但电子邮件本身是一个视图操作。 我正在寻找您如何思考要问自己哪些问题来确定将操作邮件程序方法调用放在哪里。

我已经看到/使用过它们:

  • 在模型方法中 - 相关但独立的关注点耦合不良?
  • 在模型的回调中(例如 after_save) - 据我目前的知识水平所知,最好的分离。
  • 在控制器操作中 - 只是感觉不对,但是在某些情况下这是构建代码的最明智的方法吗?

如果我想知道如何编程,我需要像程序员一样思考,因此学习如何思考特定的编程解决方案值得我独自编码数月。 谢谢你!

Sending an email is usually called after an action on a model, but the email itself is a view operation. I'm looking for how you think about what question(s) to ask yourself to determine where to put the action mailer method call.

I've seen/used them:

  • In a model method - bad coupling of related but seperate concerns?
  • In a callback in the model (such as after_save) - best separation as far as I can tell with my current level of knowledge.
  • In the controller action - just feels wrong, but are there situations were this would be the smartest way to structure the code?

If I want to know how to program I need to think like a programmer, so learning how you go about thinking through particular programming solutions is worth months of coding on my own in isolation. Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

始终不够爱げ你 2024-07-20 01:50:05

迟到的答案,但我想对这个主题进行合理化解释:

通常,在网络应用程序中,您希望发送电子邮件作为对客户的直接反应。 或者作为后台任务,以防我们谈论时事通讯/通知邮件之类的事情。

该模型基本上是一个数据存储映射器。 其逻辑应将数据处理/通信与数据存储处理封装在一起。 因此,插入与其无关的逻辑有点棘手,而且在大多数情况下是错误的。 让我们举个例子:用户注册一个帐户,应该会收到一封确认电子邮件。 在这种情况下,人们可以说,确认电子邮件是创建新帐户的直接结果。 现在,不要在 Web 应用程序中执行此操作,而是尝试在控制台中创建用户。 在这种情况下触发回调听起来是错误的,对吧? 所以,回调选项被划掉了。 我们还应该将方法写在模型中吗? 好吧,如果它是用户操作/输入的直接影响,那么它应该保留在该工作流程中。 成功创建用户后,我会将其写入控制器中。 直接地。 无论如何,在要在控制器中调用的模型中复制此逻辑都会增加不必要的模块化以及来自 Action Mailer 的 Active Record 模型的依赖性。 尝试考虑在许多应用程序上共享模型,其中一些应用程序不希望使用 Action Mailer。 由于上述原因,我认为邮件程序调用应该在有意义的地方,而通常模型不是那个地方。 试着给我举一些例子。

Late answer, but I want to rationalize on the subject:

Usually, in a web app, you want to send emails either as a direct reaction to a client. Or as a background task, in case we're talking about a newsletter/notification mail sort of thing.

The model is basically a data storage mapper. Its logic should encapsulate data-handling/communication with data storage handling. Therefore, inserting logic which does not relate to it is a bit tricky, and in most cases wrong. Let us take the example: User registers an account and should receive a confirmation email. In this case one could say, the confirmation email is a direct effect of the creation of a new account. Now, instead of doing it in the web app, try to create a user in the console. Sounds wrong to trigger a callback in that case, right? So, callback option scratched. Should we still write the method in the model? Well, if it's a direct effect of a user action/input, then it should stay in that workflow. I would write it in the controller after the user was successfully created. Directly. Replicating this logic in the model to be called in the controller anyways adds unnecessary modularity, and dependency of an Active Record model from Action Mailer. Try to consider sharing the model over many apps, in which some of them don't want Action Mailer for it. For the stated reasons, I'm of the opinion that the mailer calls should be where they make sense, and usually the model is not that place. Try to give me examples where it does make.

兮子 2024-07-20 01:50:05

嗯,要看情况。

我已经使用了所有这些选项以及您关于“为什么我应该把它放在哪里?”的观点。 很好。

如果我希望每次以某种方式更新模型时都会发生这种情况,那么我会将其放入模型中。 甚至可能在模型的回调中。

有时你只是发出一份报告; 没有任何更新。 在这种情况下,我通常会获得带有发送报告的索引操作的资源。

如果邮件程序与正在更改的模型并不真正相关,我可以考虑将其放入回调中。 我不经常这样做。 我更有可能将其封装在模型中。 我曾经这样做过,只是不经常这样做。

Well, depends.

I've used all of those options and your point about 'why should I put this where?' is good.

If it's something I want to happen every time a model is updated in a certain way, then I put it in the model. Maybe even in a callback in the model.

Sometimes you're just firing off a report; there's no updating of anything. In that case, I've normally got a resource with an index action that sends the report.

If the mailer isn't really related to the model that's being changed, I could see putting it in a callback. I don't do that very often. I'd be more likely to still encapsulate it in the model. I've done it, just not very often.

一场信仰旅途 2024-07-20 01:50:05

我知道已经有一段时间了,但最佳实践永远不会消亡,对吧? :)

根据定义,电子邮件是异步通信(确认电子邮件除外,但即使是这封电子邮件,在必须确认之前留下延迟也应该是最佳实践)。

因此,在我看来,最合乎逻辑的发送方式是:

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

Rails 的问题是它没有太多的回调(例如在 JS 中):我个人觉得这样的代码很肮脏:

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

这是同步编程中最接近回调的方式,结果邮件程序到处调用(在模型中和在控制器)。

I'm aware it's been a while but best practices never die, right? :)

Email is by definition asynchronous communication (except for confirmation email, but even this one it should be a best practice to leave a delay before having to confirm).

Hence in my opinion, the most logical way to send it is :

  • in a background action (using Sidekiq or delayed_job)
  • in a callback method : "hey this action is successfully done, maybe we can tell the world now?"

Problem in Rails is that it is not too many callbacks (as in JS for instance): I personnaly find it dirty to have code like:

after_save :callback

def callback
  if test_that_is_true_once_in_the_objects_life
    Mailer.send_email()
  end
end

So, if you really want to think like a programmer, the idea would be to set up some custom callback system in your app.

Eg.

def run_with_callback(action, callback_name)
  if send(action)
    delay.send(callback_name)
  end
end

Or even creating an event system in your app would be a decent solution.

But in the end those solutions are pretty expensive in time so people end-up writing it inline after the action

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

which is the closest fashion to callback in synchronous programming and results having Mailers call everywhere (in Model and in Controller).

七色彩虹 2024-07-20 01:50:05

控制器成为邮件发送者的好地方有几个原因:

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

There's several reasons why controllers are a good place for the mailers:

  • Emails that have nothing to do with a model.
  • If your emails depend on several models that dont know about each other.
  • Extracting models to an API should not mean reimplementing mailers.
  • Mailer content determined by request variables that you dont want to pass to the model.
  • If your business model requires a lot of diferent emails, model callbacks can stack.
  • If the email does not depend on the result of model computations.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文