【问题标题】:How can I handle errors in Rails model, which doesn't have controller and views如何处理没有控制器和视图的 Rails 模型中的错误
【发布时间】:2019-03-29 04:00:36
【问题描述】:

我有一个模型,它是我的 Rails 应用程序和 API 之间的桥梁,没有控制器和视图。

在下面的方法中我得到一个错误,这是一个ActiveResource::ResourceNotFound 错误。


      def find_order(order_id, cached: false)
        within_temp_session do
          order = find_cached_order(order_id) if cached
          unless order
            order = API::Order.find(order_id)  # here the order can be absent
            cache_order(order.attributes)
          end
          order
        end
      end

我的想法从各个角度来看都不好,比如在模型中调用控制器方法违反了 MVC 概念。

编辑redirect_toflash[:alert] 不自然工作,以及errors.add error

使用attr_accessor 有助于向模型实例添加错误,但我不会在任何地方使用模型实例。

如何通知用户发生了错误?

这是回溯:

10 File "/app/app/models/model1.rb", line 24 in block in find_order
11 File "/app/app/models/model1.rb", line 97 in block in within_temp_session
+ 1 non-project frame
13 File "/app/app/models/model1.rb", line 97 in within_temp_session
14 File "/app/app/models/model1.rb", line 21 in find_order
15 File "/app/app/models/model2.rb", line 76 in find_order
16 File "/app/app/models/model3.rb", line 45 in order
17 File "/app/app/models/model3.rb", line 69 in build_call
18 File "/app/app/models/model3.rb", line 50 in shipping_label_form
19 File "/app/app/models/model3.rb", line 55 in create_label
20 File "/app/app/jobs/job.rb", line 8 in block in perform
+ 2 non-project frames
23 File "/app/app/jobs/job.rb", line 7 in perform

编辑 2: 用户点击get shipping label按钮,触发ShippingLabelsController中的:new动作,预填表单并触发创建标签的延迟作业的:perform动作。并且错误发生在作业开始后。

【问题讨论】:

  • 你在哪里称呼“find_order”?您可以在该调用周围添加一个开始/救援语句以捕获 ResourceNotFound 说明
  • “我如何通知用户” - 用户首先如何获得此方法?
  • 用户尝试为订单创建运输标签并在后台进入此方法
  • 那么,正如 arieljuod 所说,您可以在运输标签控制器中进行救援。例如,rescue_from 在控制器级别。或begin/rescue 在动作正文中。
  • perform 方法在哪里被调用?您需要提供触发该代码的请求的上下文,如果您不解释完整的流程“用户尝试创建运输标签”不清楚,则不可能提出任何建议,什么控制器/操作/代码由触发用户的那个动作?

标签: ruby-on-rails


【解决方案1】:

SomeJob.perform_later 触发异步作业。我们不知道它什么时候会完成。所以是的,通知用户有错误是很棘手的。但是需要通知用户吗?

排队作业的好处是,如果它们失败了,您可以再试一次。然后再次。再一次,直到他们工作或你放弃。当您使用 API 时,API 和网络会出现临时错误,这些错误会自行解决。不要用这些来打扰用户。

ActiveJob has retry_on 告诉作业要重试哪些异常。

class SomeJob < ApplicationJob
  retry_on ActiveResource::ResourceNotFound

  ...
end

现在,如果出现 API 故障,您的作业将悄悄重试。

ActiveResource::ResourceNotFound 是一个相当粗略的异常,可能由于多种原因发生,因此您最终需要在模型中捕获并重新抛出更具体的异常以微调错误处理。


重试有限制。如果重试次数用尽,则需要人工参与并查看问题所在。那个人不是用户,他们不知道如何解决它,它是管理员。

retry_on 用尽其尝试时,异常将冒泡到底层队列系统,然后该系统应通知管理员队列中有一个死项目。具体取决于您使用的排队系统。


如果确实需要通知用户,有多种选择。一种是将一系列错误添加到 User 模型中。 UI 会弹出并显示用户的错误数组中的任何错误,可能会在一瞬间显示。

然后您将用户传递给作业。如果作业有任何错误,它们将被捕获并添加到其关联的用户错误数组中。下次该用户使用您的 UI 时,他们会看到错误。

【讨论】:

  • 或者,如果用户需要被通知,job可以发送邮件什么的。
  • @SergioTulentsev 我已经画了一个草图,说明如何为用户排队错误并稍后显示它们。
  • 或者类似的,是的。电子邮件的优点是不需要用户登录。如果过程很重要,可能会很有用。当然,如果你觉得花哨,他们可以创建一个完整的通知子系统。具有可发送电子邮件和不可发送电子邮件的通知类型等。
  • 妈的,一想到这个我就手痒痒的。很好的软件设计练习。 :)
  • 出现此错误的原因是用户尝试访问的订单由于访问令牌过期而无法访问。所以,我知道它发生了,我和用户将无能为力。我想让用户知道他们应该停止尝试访问订单的错误。
猜你喜欢
  • 2011-08-05
  • 1970-01-01
  • 2018-02-11
  • 2012-01-31
  • 1970-01-01
  • 2010-09-09
  • 2011-10-19
  • 2015-11-03
  • 1970-01-01
相关资源
最近更新 更多