Rails控制器 - 仅当Rails UJS方法内部成功时才执行操作(相互依赖的方法)

时间:2016-06-09 15:16:18

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-4 ujs

关注另一个问题(Rails controller - execute action only if the two methods inside succeed (mutually dependent methods)),我想确保在我的一个控制器操作中,如果用户没有看到Rails UJS方法显示的消息,那么第一个方法控制器动作的任何一个都没有实现。

CONTEXT

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

我的问题如下:如果在控制器中间超时,我想避免更新User表(通过方法1),更新UserDeal表(通过方法2)但不是thrid方法,即显示消息FAILS的ajax请求(错误,超时,...状态如500或404或取消或超时......)。

在我的应用中,对于移动用户而言,如果他们是在有互联网连接的地铁中,他们就会启动通过&#39; example_action&#39;控制器,成功执行第一种方法(1)和第二种方法(2),但随后他们进入隧道60秒,非常低(<5b /秒)或没有互联网连接,因此出于UX原因,我超时请求并向用户显示'抱歉花了太长时间,再试一次&#39;。问题是,如果我无法向他们显示结果(3),我需要能够不执行(1)和(2)。

我需要两种方法(1)和(2)以及(3)相互依赖&#34;如果一个不成功,则不应该执行另一个。这是我描述它的最佳方式。

今天这是我的代码。它没有工作,因为我通过点击手动测试,然后在2秒后我断开了互联网连接。我在我的数据库中看到(1)和(2)已经执行并且数据库已更新,但我看到了消息“抱歉花了太长时间,再试一次”。

这是正确的方法吗?如果是的话怎么做? 如果没有,我应该尝试不同的角度:if(1)和(2)是否成功但不是(3)我应该存储轨道UJS xhr状态是错误还是超时,因此模态wxas无法有效显示给用户,然后在他们重新上线后向他们显示结果/消息?

这是代码

用户的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设置。

重要提示:在这里,如果出现错误或超时,我会发送错误/超时模式消息代替您通常获得的消息(请参阅上面的#34;此处是你的结果..&#34;)

$(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);
  };
});

1 个答案:

答案 0 :(得分:1)

因此,只有在抛出错误时,事务才会回滚。如果抛出未处理的错误,您的应用程序将崩溃并以某种方式显示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 %>

修改

处理连接问题绝对是棘手的,并不是一个理想的解决方案。我通常会让数据库继续不间断地让它返回成功或失败的时间。对于冗长的事务,您可以使用像delayed_jobsidekiq这样的gem在后台处理操作,并让rails控制器返回一个响应,说明&#34; ...等待......&# 34;或者其他的东西。除非您在前端使用websockets,否则这意味着不断使用ajax请求轮询服务器,以查看后台进程是否完整。