Rails controller - 只有在 Rails UJS 方法成功时才执行动作(相互依赖的方法)

Rails controller - execute action only if the a Rails UJS method inside succeed (mutually dependent methods)

在另一个问题 () 之后,我想确保在我的控制器的一个操作中,如果用户没有看到 Rails UJS 方法显示的消息,那么控制器操作的第一个方法也未实现。

上下文

我有一个控制器,其方法名为 'actions'。当应用进入方法 'example_action' 内部时,它会实现第一个方法 (1) update_user_table,然后 (2) 另一个 update_userdeal_table。 (两者都将读取和写入数据库)然后 (3) 与 Rails UJS(ajax) 调用相关的第三种方法。

我的问题如下:在控制器中间超时的情况下,我想避免更新 User table(通过方法 1),UserDeal table 已更新(通过方法 2)但不是第三种方法,即显示消息失败的 ajax 请求(错误、超时、...状态如 500 或 404 或已取消或超时...)。

在我的应用程序中,对于移动用户,如果他们在有互联网连接的地铁中,他们会启动通过 'example_action' 控制器的请求,成功执行第一种方法 (1) 和第二种方法 (2) ) 但随后他们以非常非常低(<5b/秒)或无互联网连接进入隧道 60 秒,因此出于 UX 原因,我将请求超时并显示给用户 'sorry it took too long, try again'。问题是,如果我不能向他们显示结果 (3),我需要能够不执行 (1) 和 (2)。

我需要(1)和(2)和(3)这两个方法"mutually dependent":如果一个不成功,另一个就不要执行了。这是我能描述的最好的方式。

今天这是我的代码。它不起作用,因为我通过单击进行手动测试,然后仅 2 秒后我断开了互联网连接。我在我的数据库中看到执行了 (1) 和 (2) 并且数据库已更新,但我看到消息 'sorry it took too long, try again'.

这是正确的做法吗?如果是,该怎么做? 如果不是,我是否应该尝试不同的角度,例如:如果 (1) 和 (2) 成功但不成功 (3) 我是否应该存储 rails UJS xhr 状态是错误或超时的事实,因此模态wxas 没有有效地显示给用户,然后在他们重新上线后向他们显示 result/message?

这是代码

html 用户页面 用户单击触发 Rails UJS aajax 请求的按钮,该请求最终将显示模态消息

<div id=zone"> 
   <%= link_to image_tag(smallest_src_request),
          deal_modal_path,
           remote: true %>
</div>

此发送到指向此控制器操作的路由

交易控制者

class DealsController < ApplicationController
  def deal_modal
    Deal.transaction do
       update_user_table # that's the (1)
       update_userdeal_table  # that's the (2)
       # show_modal_message
       respond_to do |format|
         format.js
       end  
  end

  private
  def update_user_table
    # update the table User so it needs to connect to internet and acces the distant User table
  end
  def update_userdeal_table
    # update the table UserDeal table so it needs to connect to internet and access the distant UserDeal table
  end
end

这指向一个 js.erb 视图文件

deal_modal.js.erb

showModalMessage("Here is your result <variable and all>);

为了管理 ajax、错误、超时...(如果需要解决问题),我使用 Rails UJS 设置。

重要提示: 在这里,如果出现错误或超时,我会发送错误/超时模式消息来代替您通常收到的消息(见上文) "Here is your result..")

$(document).on('page:change', function () {
      $("#zone").
        on('ajax:error',function(event,xhr, status, error){
          console.log(' ajax call failed:', error);
          var msg;
          msg = Messenger().post({
            hideAfter:  4, 
            message:    "sorry it took too long, try again."
          });
    });

$(document).on('page:change', function () {
  //set timeout Rails UJS ajax option that will display message for ajax:error cases defined above
  $.rails.ajax = function(options) {
    if (!options.timeout) {
      options.timeout = 5000;
    }    
    return $.ajax(options);
  };
});

所以事务只有在抛出错误时才会回滚。如果抛出未处理的错误,您的应用程序将崩溃并以某种方式显示 500 错误。

为了向用户显示响应,无论是成功还是错误,您都需要渲染一些东西。所以你不想阻止 respond_to 块的执行。处理此问题的一种方法是通过实例变量设置标志。

def deal_modal
  begin
    Deal.transaction do
      update_user_table
      update_userdeal_table
    end
    @success = true
  rescue
    @success = false
  end
  # show_modal_message
  respond_to do |format|
    format.js
  end  
end

然后在deal_modal.js.erb

<% if @success %>
  showModalMessage("Here is your result <variable and all>");
<% else %>
  showModalMessage("There was a problem");
<% end %>

编辑:

处理连接问题确实很棘手,而且没有真正理想的解决方案。我通常会让数据库不间断地继续运行,并让它 return 根据自己的时间决定成功或失败。对于冗长的事务,您可以使用 gem 之类的 delayed_job or sidekiq 在后台处理操作,并让 rails 控制器 return 响应“...待处理.. 。“ 或者其他的东西。除非你在前端使用 websockets,否则这意味着不断地用 ajax 请求轮询服务器以查看后台进程是否完成。