Rails - 用动态变量修改 %p 的文本

Rails - modify text of %p with dynamic variable

我有一个基本表单,提交后会触发对外部 API 的创建请求。提交时,会出现一个带进度条的阶段值,而不是“提交”按钮。创建过程在外部 API 上需要时间,因此我不得不使用 while status == 'inactive' 每秒 运行 几个显示请求,并在显示请求响应具有 status: 'active' 时停止。 每个 Show 请求响应还包含一个 'stage' 属性,它显示创建过程的阶段(连接、创建、获取、完成等)。对于每个请求,当前阶段都存储在@stage 变量中,可以使用 ApiRequest.stage 访问该变量。每个 API 相关的东西都在服务文件中。

我用阶段+进度条更改提交按钮的coffeescript:

$('#new_connection').on 'submit', ->
    button = $('#submit_button')
    progress = $('.loading')
    button.fadeOut 500
    setTimeout (->
      if button.is(':hidden')
        progress.fadeIn 500
      return
    ), 509
    return

以及阶段+进度条部分:

.loading
  %p.center-align#stage <!-- This should display the stage in real time -->
  .progress <!-- This is a materializecss progress bar -->
    .indeterminate

如何在每次值实时更改时将 #stage 中的文本更新为 ApiRequest.status,保持在同一页面上,从提交表单的那一刻到结束(它无论如何都会在后台完成所有工作后重定向到 create.html?

要实时或至少接近实时显示您的操作状态,您必须

  • 定期轮询服务器以查看状态是否已更改 - 也就是说,每隔一两秒持续点击 show 端点并在成功回调中更新状态标签
  • 或者您可以实施一种方案,让服务器在状态发生变化时使用 WebSocket、长轮询或其他技术通知页面。

轮询就像你在开车,而你的一位乘客每秒都在问 "are we there yet?"。它不是很有效,特别是如果操作需要很长时间,因为每 n 秒发出一个单独的 HTTP 请求,只会返回 "still in progress" 响应。但它很容易实现,所以如果 show 动作很快并且操作本身相当快地完成,那么它可以是一个很好的折衷方案。

另一种方法是让服务器在状态发生变化时通知您。为此,您需要有一个发布者-订阅者基础设施。如果您使用 Rails 5,Action Cable is probably your best option as it is built right into Rails. You can find a detailed comparison of the different available technologies here: In what situations would AJAX long/short polling be preferred over HTML5 WebSockets?

如果您使用的是轮询,则可以将 success 常规 AJAX 调用的回调中的状态标签更新为 show。如果 show 仅呈现 HTML,那么您将不得不从 AJAX 响应数据中解析出新状态:

<!-- example output of show.html.erb -->
<!-- ... -->
  <div id="current-status"><%= @status %></div>
<!-- ... -->

示例 JavaScript 用于解析 AJAX 响应中的页面并获取 #current-status <div>:

的值
setTimeout(function() {
  $.get({
    url: "<%= show_page_path %>",

    success: function(data) {
      var response = $("<div></div>").
        append($.parseHTML(data, null, true));

      $("#current-status").html(
        $("#current-status", response)
      );
    },
  });
}, 1000);

当然,如果您为仅包含状态的 show 操作添加 JSON 端点:

# in the controller
respond_to do |format|
  format.html
  format.json do
    render json: { status: @status }
  end
end

那么你不必做任何HTML解析:

setTimeout(function() {
  $.get({
    url: "<%= show_page_path(format: :json) %>",

    success: function(data) {
      $("#current-status").text(data.status);
    },
  });
}, 1000);

示例未经测试,因此如果不进行一些修改,它们可能无法完美运行。

好的,所以您要做的就是在控制器中创建一个方法来读取变量:@stage = your method here.
format.json { render json: { stage: @stage } }写一个respond_to do |format|
现在你必须为这个自定义控制器方法创建一个路由:get '/your/link', to: 'controller#custom_method', as: 'stage'.
剩下的就是通过Ajax:

触发这个方法
$.get({
  url: "your/link.json",
  success: function(data) {
    $('#your_paragraph_id').text(data['stage]);
    },
});

您可以将此 Ajax 调用放在 setInterval 函数中。