我目前正在开发一个Rails应用程序,该应用程序必须与外部Web API通信,从结果中更新DB记录并异步更新视图。
我有一个list
操作,我直接从数据库中显示数据,其中包含一个在分页表中发送的电子邮件列表。呈现视图后,我需要向应用程序(在不同的路径上)发出一个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
,它会呈现实际table
的部分内容:
# 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>
对于首先加载表的操作和处理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
当页面首次加载时,它从控制器加载,并且AJAX请求被正确发送,但如果我转到下一页(发送具有不同GET参数page
的请求),页面直接从控制器加载,但是发送了两个AJAX请求,一个用于第一页,一个用于第二页,如下所示,并且table
有点的HTML随机更改,而不是真正显示正确的数据table
:
我曾经有过JavaScript,它在body
而不是header
中定义了AJAX请求,但是这样的请求只会在每次更改页面时保持重复,每次请求都会有越来越多的请求时间。我做了一些搜索,发现通过将代码移动到head
可以修复额外调用的问题。
我真的不知道我的问题是否与Turbolinks处理请求的方式有关,但我需要的是应用程序呈现完整视图然后发送完全相同的GET
的AJAX请求params到一个不同的动作,只是用表格呈现部分。
非常感谢任何帮助!
答案 0 :(得分:1)
由于_mail_list_loader.js.erb
中有动态内容,您可能会注意到<head>
中的脚本标记在后续页面加载时被复制。虽然它是作为一个代码块编写的,但Turbolinks并没有&#34;看到&#34;就这样,并在每个负载上附加一个新的脚本元素。
我建议您尝试将尽可能多的JavaScript移动到.js
文件中并将其包含在应用程序清单中。您可以通过将它们作为属性呈现来获取动态服务器生成的变量,并让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
回调应确保响应将列表呈现为正确的元素(而在此之前,如果某人快速分页,则可能存在第3页上呈现第2页列表的风险)。
希望有所帮助。
答案 1 :(得分:0)
从我在this answer中看到的,在某些链接上禁用Turbolinks正是我为了完全重新加载我的JavaScript所需要的,所以我去了发送请求更改参数的分页链接(例如{{ 1}})并简单地将do {
...
} while((again == 'y') || (again == 'Y'));
添加到其中。
现在没有额外的AJAX调用,因为链接现在只渲染整个HTML,而不是通过Turbolinks。