如果从外部 api 获取的内容返回 500,我该如何渲染 ruby on rails .erb 模板?

How can I render a ruby on rails .erb template if something being fetched from an external api returns a 500?

提问人:PhilCowan 提问时间:1/5/2023 更新时间:1/5/2023 访问量:133

问:

我有一个管理页面,可以在其中更改用户电子邮件模板。现在 MailChimp/Mandrill 出现中断,它正在使我的应用程序崩溃。

这是使页面崩溃的行,当我将其注释掉时,它会很好地加载页面

<%= render 'super_admin/shared/select', f: f, what: :email_template_name, collection: MandrillWrapper.template_names %>

崩溃时显示日志

17:25:06 dev.1  | Mandrill::Error (We received an unexpected error: <html>
17:25:06 dev.1  | <head><title>502 Bad Gateway</title></head>
17:25:06 dev.1  | <body bgcolor="white">
17:25:06 dev.1  | <center><h1>502 Bad Gateway</h1></center>
17:25:06 dev.1  | <hr><center>nginx/1.12.2</center>
17:25:06 dev.1  | </body>
17:25:06 dev.1  | </html>
17:25:06 dev.1  | ):

所以我知道是 Mandrill,我检查了一下,他们现在有中断。

我试过了

<% if MandrillWrapper.template_names.present? %>
<%= render 'super_admin/shared/select', f: f, what: :email_template_name, collection: MandrillWrapper.template_names %>
    <% else %>
    <p>templates currently unavailable</p>
  <% end %>

<% begin %>
<%= render 'super_admin/shared/select', f: f, what: :email_template_name, collection: MandrillWrapper.template_names %\>
<% rescue %>
<p>templates currently unavailable</p>
<% end %>
Ruby-on-Rails 错误处理 ERB

评论

1赞 max 1/5/2023
不要在没有您打算挽救的特定错误类的情况下使用。这是一种称为神奇宝贝异常处理的反模式,您实际上只是在搬起石头砸自己的脚,因为它会产生一个可以吞噬任何东西的黑洞。你也不应该在需要拯救的观点中做任何事情。视图应该只是从控制器获取数据,并以最简单的方式将其呈现为 HTML。rescue

答:

3赞 Jarno Lamberg 1/5/2023 #1

根据您的描述,正在进行失败的外部 API 或其他调用。MandrillWrapper.template_names

首先,我会将外部调用移动到控制器,在那里我可以正确处理错误,然后将任何适当的内容传递给视图,以显示要修改的电子邮件模板或一些消息,告诉用户稍后再试。在控制器操作中处理外部调用可以比在视图中更轻松地对其进行测试。

作为改进代码的第二步,我会将外部调用的处理移动到控制器操作将调用的服务或表示器对象。同样,这将使测试操作变得更加容易。

最后,作为第三个改进步骤,您可以通过将外部调用移动到后台作业来“自动执行”或计划外部调用,这样您就不必在控制器操作运行时但在运行之前进行调用。为此,您必须在数据库中存储一些东西,但这会使页面呈现速度更快,并再次简化测试。

最后一步对你来说是否可行取决于你的业务和应用程序的许多事情,根据你的描述,我无法知道这些事情。不过,如果您决定走这条路,我和其他人可以帮助您解决进一步的问题:)

评论

0赞 PhilCowan 1/5/2023
确切地说,外部 api 调用失败了。是的,我认为最简单的解决方案是将其移动到控制器。我希望有一种更简单/更懒惰的方法来做到这一点:)
1赞 max 1/5/2023
将代码移动到控制器中只是可测试性的一个非常微不足道的改进,因为控制器也是出了名的难以测试。而是将外部 API 调用移动到从控制器调用的服务对象或作业,并缓存其结果。
0赞 Jarno Lamberg 1/6/2023
@PhilCowan,如果它回答了你的问题,你介意将我的答案标记为已接受的答案吗?
1赞 PhilCowan 1/6/2023
我会接受它,当我有时间时,我会根据你的答案重构代码。