【问题标题】:javascript being sent everytime ajax requests rails app每次 ajax 请求 rails app 时都会发送 javascript
【发布时间】:2014-02-22 05:51:40
【问题描述】:

我有一个通过这个 ajax 获得跨域请求的 Rails 应用程序(我使用 rack-cors 来完成这个没有 jsonp 的跨域请求):它用 html 响应

  //to ensure cache=true gets passed
  $.ajaxPrefilter('script', function(options) {
  options.cache = true;
  });

   //ajax requests html
   $.ajax({
  beforeSend: function (xhr) {
      xhr.setRequestHeader ('Authorization', api_key);
  },
  dataType: 'html',
  type: 'GET',
  url: url+'/gwsearch/ajax_search?d1='+d1_val+'&d2='+d2_val,
  crossDomain: true,
  success:function(result){

    $("#display").html(result);
  },
  error: function(result) {
    $('#display').html('Unauthorized client.');
  }

它以#display 中显示的HTML 进行响应。它在 html 中包含此脚本标记

  <script src="http://localhost:3000/assets/application.js" type="text/javascript"></script>

我在新显示的 Rails 应用上有输入按钮,它们看起来像这样:

   <%= form_tag plans_collapse_plans_path, :method => 'post', :remote => true do %>
      <%= hidden_field_tag(:plangroup_id, plangroup.id) %>
      <%= image_submit_tag "collapse.png" %>
   <% end %>

单击输入按钮执行 POST。问题是输入按钮将发布与我请求跨域 Rails 应用程序一样多的次数。如果我已请求该应用程序 5 次,当我单击应用程序上的输入按钮时,它将 POST 5 次。

无论我发送多少次初始 ajax 请求,我仍然只有一个 application.js;它不会被物理缓存超过一次。

编辑:这是我的缓存的样子,如您所见,只有一个 application.js:

collapse_tplans POST 都对应同一个 application.js 文件,同一行。如果我已经加载了 6 次初始 ajax 请求,我将有 6 个来自 application.js 的 collapse_tplan POST

我的猜测是,正在发送的 html 页面中的脚本标记正在初始化 jquery 的新版本(因为 jquery 包含在 application.js 中),并且可能与 application.js 中加载的其他内容重复通过脚本标签发送的时间。话虽如此,在 Chrome 中的网络下,无论我执行多少次 ajax 请求,我都只能看到 application.js 被请求一次。

有什么想法吗?我需要我的输入按钮只发布一次,就像它应该做的那样。我真的被这个难住了。

【问题讨论】:

  • I still only have one application.js present - 这是什么意思?我很困惑你的问题是什么?
  • @RichPeck 我用我的缓存图片更新了问题。我的意思是,虽然我在缓存中只有一个 application.js,但每次我从初始 ajax 请求中获得 HTML 响应时,它都会包含一个指向同一个 application.js 的脚本标记。问题是每次我在 HTML 响应中提交输入时,它都会发布与加载该脚本标签一样多的次数。即,如果我加载 HTML 响应 3 次,我将有 3 个来自我的输入的 POST。这些应该只发布一次。它们都指向同一个发起者:application.js
  • @RichPeck 我的意思是,即使 application.js 被缓存了一次,它似乎每次加载 HTML 页面时都会重新初始化,为输入事件创建新的处理程序。这是我的猜测。
  • 我仍然不明白为什么您认为这与您的缓存显示的内容有关。在通过 AJAX 加载的 HTML 代码中有一个 script 元素,jQuery 将其放入文档中以便执行。我不知道你为什么认为缓存应该防止这种情况发生。
  • 是的。 // jQuery.ajax 的文档指出,响应中包含的 dataType:html 脚本元素在插入 DOM 时会被评估。您可以尝试改用dataType:text,看看是否会改变行为。否则,您可能必须自己过滤掉那些脚本元素;或确保您的脚本不会多次附加相同的事件。

标签: javascript jquery ruby-on-rails ajax ruby-on-rails-3


【解决方案1】:

由于您在表单上使用 remote:true,我的理论是每次加载脚本时 rails.js 都会在文档元素上附加一个委托事件。 5 次加载 = 5 次事件 = 5 次 ajax 调用。

要修复它,您可以:

  1. 删除远程 true 并自行滚动确保它只发生一次。
  2. 在加载新脚本之前删除文档上的委托事件。

试试:(我猜这里)

success:function(result){
  $(document).undelegate('submit.rails');
  $("#display").html(result);
},

解释:

每次 rails.js 运行时,都会将 submit.rails 事件添加到文档上的事件堆栈中。当您将 html 插入页面时,rails.js 代码就会运行。所以,我们首先取消对事件的委托,然后再加载事件。

【讨论】:

  • 1.我们正在使用 rack-cors 绕过 CORS 并允许我们在没有 jsonp 的情况下跨域做一些事情。我们已经尝试过推出自己的产品,但由于同源政策,它不会起作用。我不知道 rack-cors gem 是如何工作的,但我知道它的代码在我们执行:remote =&gt; true 2 时会被命中。你能解释一下如何实现吗?
  • 另外,jquery 每次都重新初始化怎么办?这是一个实际问题还是不可能?
  • @jamesdlivesinatree 我不认为 jquery 是一个问题,但 rails.js 是因为它会再次定义事件。
  • 到目前为止,这在很大程度上是有效的。有几次我第一次尝试它,在第二次运行调用后出现“未找到模板”错误。
  • 您能解释一下为什么会这样吗?我不明白为什么如果我每次都取消委派submit.rails,表格甚至仍然提交。我没有任何类型的初始化标志,它是如何工作的?
【解决方案2】:

正如@natedavisolds 所说,我猜你的application.js 脚本被执行了5 次,而你的buttonclick 处理程序或你的formsubmit 处理程序被附加了5 次。

application.js 仅被请求一次这一事实并不能告诉您它被执行了多少次

尝试在application.js 脚本的开头添加以下行:

console.log('application.js executed');

并检查您的浏览器控制台以查看该消息出现了多少次。


根据您的脚本名称application.js,我猜它是为了初始化整个页面,而您的ajax 请求看起来只是用搜索结果填充#display 节点。

你将不得不重构你的 application.js 文件:

  • 阅读application.js 文件中的代码,并将代码分成两部分:涉及设置#display div 的部分和其余部分。
  • 将第一部分移动到单独的results.js(或您认为合适的任何名称)中。
  • 从对/gwsearch/ajax_search 请求的响应中删除&lt;script src="application.js"&gt; 节点,并将其替换为&lt;script src="results.js"&gt; 节点

【讨论】:

  • 添加了console.log 语句,正如你猜到的,每次我运行ajax 时都会执行。
  • 如何构造一个 form.js 文件并单独提供它? 1.每次加载html页面时都会再次加载和处理,给我同样的问题,不是吗? 2. 我们尝试构建自己的表单代码,但它并没有让我们绕过 CORS(我们的 rack-cors gem 让我们这样做,并且将代码放入 application.js)。有没有一种方法可以构建和服务form.js,同时仍然让 Rails 处理我的表单?如果没有,从这里处理这个问题的最佳方法是什么?
  • 其实,有没有办法在application.js加载之前检查,之前是否已经加载过?我试过你的方法,但由于新的application.js 加载,我永远找不到我设置的变量。是否有任何其他类型的标识符可以用来确定它之前是否已加载?另外,我如何将它放在 application.js 中的所有代码之前?它说所有东西都将放在清单下面。
  • 简而言之,我想找到某种固有标志来告诉我 application.js 之前是否运行过,如果flag == true 运行,我可以把它放在哪里以防止我的application.js 运行
  • 感谢您的编辑,您能告诉我如何从我的 html 页面中删除 application.js 吗?这会自动与每个带有 rails 的 HTML 文件一起提供。我怎样才能禁用它?这样我可以将我的父页面(客户端)链接到脚本,这样它只会被调用一次。
【解决方案3】:

这个问题的答案是阻止我的应用程序为application.js 提供服务并将其托管在客户端上。我通过以下方式做到了这一点:

app/views/layout/application.html.erb

我注释掉了服务application.js的部分

<!--#  <%= javascript_include_tag "application" %> -->

在我的客户端中,我添加了

<script src="https://myapp.herokuapp.com/assets/application.js"></script>

因此客户端服务于application.js,并且在没有application.js 的情况下发送了rails html 响应。希望这对每个人都有意义,我花了一段时间才拼凑起来!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    相关资源
    最近更新 更多