jquery - 如何在 Rails 上启用 Turbolinks 的情况下通过 AJAX 正确渲染部分内容?

标签 jquery ruby-on-rails ajax ruby-on-rails-5 turbolinks

我目前正在开发一个 Rails 应用程序,该应用程序必须与外部 Web API 通信、根据结果更新数据库记录并异步更新 View 。

我目前在做什么

我有一个 list 操作,其中直接显示来自数据库的数据,其中包含在分页表中发送的电子邮件列表。渲染 View 后,我需要向应用程序发出 AJAX 请求(在不同的路线上),该应用程序向外部 Web API 发出请求,更新数据库,然后使用 table 渲染部分包含所有电子邮件,与原始 list 操作中呈现的电子邮件相同。

以下代码处理 AJAX 请求:

# _mail_list_loader.js.erb
document.addEventListener("turbolinks:load", function() {
  $.ajax({
    url: '/certified_mail/mail_list',
    type: 'get',
    data: {
      page: <%= @page %>,
      rut: <%= @rut || 'null' %>,
      from: <%= @from || 'null' %>,
      to: <%= @to || 'null' %>,
      ids: <%= @outdated_message_ids.to_json.html_safe %>
    }
  });
});

哪个响应是一个.js.erb,它呈现实际的一部分:

# mail_list.js.erb
$('#mail-list').html('<%= j render 'certified_mail/mail_list' %>');

_mail_list_loader.js.erb 在我的 application.html.erb 中呈现:

# application.html.erb
<head>
    ...
    <script><%= render 'certified_mail/mail_list_loader.js' %></script>
</head>

我的 Controller 对于首先加载表的操作和处理 AJAX 请求的操作如下所示:

class CertifiedMailController < ApplicationController
  def list
    if params[:page].nil? || params[:page].to_i <= 0
      redirect_to action: :list, params: {
        page: 1,
        from: params[:from].to_s.empty? ? nil : params[:from],
        to: params[:to].to_s.empty? ? nil : params[:to]
      }
    else
      # Handle filters and get emails from the DB
    end
  end

  def mail_list
    if request.xhr?
      # Make API request, update accordingly,
      # handle filters and get emails from the DB
      respond_to do |format|
        format.js
      end
    else
      redirect_to action: :list
    end
  end
end

我的问题是什么

当页面首次加载时,它从 Controller 加载,并且 AJAX 请求已正确发送,但是如果我转到下一页(使用不同的 GET 参数 page 发送请求) ,页面直接从 Controller 加载,但是发送了两个 AJAX 请求,一个用于第一页,一个用于第二页,如下所示,并且 table 的 HTML 有点随机变化,而不是在中真正显示了正确的数据:

Network log from Firefox

我曾经使用 JavaScript 在 body 中定义 AJAX 请求,而不是在 header 中,但这样请求就会在每次页面更改时不断重复,每次都有越来越多的请求。我做了一些搜索,发现可以通过将代码移动到 head 来解决额外调用的问题。

我真的不知道我的问题是否与 Turbolinks 如何处理请求严格相关,但我需要的是应用程序呈现完整 View ,然后使用完全相同的 GET< 发送 AJAX 请求 参数传递给仅使用表格呈现部分内容的不同操作。

任何帮助将不胜感激!

最佳答案

因为_mail_list_loader.js.erb中有动态内容您可能会注意到 <head> 中的脚本标记在后续页面加载时会重复。尽管它是作为一个代码块编写的,但 Turbolinks 不会以这种方式“看待”它,而是在每次加载时附加一个新的脚本元素。

我建议您尝试将尽可能多的 JavaScript 移至 .js文件并将它们包含在您的应用程序 list 中。您可以通过将服务器生成的动态变量渲染为属性并让 JS 获取它们来获取它们。

例如,您可能想尝试以下操作:

# app/views/certified_mail/list.html.erb
<% props = { page: @page, rut: @rut, from: @from, to: @to, ids: @outdated_message_ids } %>
<table data-component="mail-list" data-props="<%= props.to_json %>" id="mail_list_<%= @page %>">
 …
</table>
<小时/>
# app/assets/javascripts/load_mail_list.js
;(function () {
  function loadMailList (data, callback) {
    $.ajax({
      url: '/certified_mail/mail_list',
      type: 'get',
      dataType: 'html',
      data: data,
      success: callback
    })
  }

  $(document).on('turbolinks:load', function () {
    var $element = $('[data-component=mail-list]')
    loadMailList($element.data('props'), function (html) {
      $element.html(html)
    })
  })
})()
<小时/>
# app/controllers/certified_mail_controller.rb
def mail_list
  if request.xhr?
    # Make API request, update accordingly,
    # handle filters and get emails from the DB
    render 'certified_mail/mail_list'
  else
    redirect_to action: :list
  end
end

回调应确保响应将列表呈现到正确的元素中(而以前,如果有人快速分页,则可能存在将第 2 页的列表呈现在第 3 页上的风险)。

希望有帮助。

关于jquery - 如何在 Rails 上启用 Turbolinks 的情况下通过 AJAX 正确渲染部分内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46550651/

相关文章:

ruby-on-rails - rails 3 教程 : rspec + factory_girl_rails problem

javascript - 如何暂时禁用 Ajax 调用中的按钮?

php - 在此 AJAX 场景中最好的安全准则是什么,特别是身份验证?

javascript - 使用 onbeforeunload 事件,选择停留在此页面时 url 发生变化

javascript - JQUI datepicker 隐形日期 bug

javascript - 无法访问 POST 中所有动态添加的表元素

javascript - 多次触发 Jquery 事件

jquery - 从不同域加载页面的最快方法

ruby-on-rails - 发出 JSON 错误输出而不是 JSON 请求的 HTML

ruby-on-rails - 是什么导致 Ruby 2.0.0/Postgres 9.3/Rails 4.2 中的 CSV 导出截断文本