Ruby on Rails如何防止Turbolinks劫持AJAX请求

5

我正在遵循RoR入门指南,并在学习过程中添加一些内容。具体来说,我想在第 5.13 删除文章 步中使用AJAX删除文章而不是使用标准模式。

我希望以最符合RoR方式的方式实现这一点。在阅读了在Rails中使用JavaScript一章后,以下步骤似乎是可行的:

  1. remote: true 属性添加到 link_to 帮助程序(请参见代码片段A)
  2. 通过添加 data:{turbolinks:false} 来禁用 turbolinks 这个 link_to 帮助程序(请参见代码片段A)
  3. 在控制器中添加一些逻辑,以确保返回JSON(请参见代码片段B)
  4. 添加监听 ajax:success 事件的 JavaScript,然后对该项目进行动画处理(请参见代码片段C)

片段 A

<td><%= link_to 'Destroy', 
        article_path(article),
        method: :delete,
        data: {turbolinks: false, remote: true},
        :class=> 'remove-article' %></td>

段落标签Snippet B
def destroy  
    @article = Article.find(params[:id])

    respond_to do |format|
      if @article.destroy
        format.html { redirect_to articles_path }
        format.json { render json: @article }
      else
        format.html { render action: "index" }
        format.json { render json: @article.errors, status: :unprocessable_entity }
      end
    end
 
end
片段 C
(function(){
  $(document).on('turbolinks:load', listenForArticleDelete);

  function listenForArticleDelete() {
    $('a.remove-article').on('ajax:success', function(e, data, status, xhr) {
      // e.preventDefault();
      console.log('DELETE: AJAX SUCCESS', e, '\n', data, '\n', status, '\n', xhr);
    });
  }
})();

这不是我预期的工作方式:
  • 禁用turbolinks没有生效:它仍然替换了整个页面内容。
  • 事件ajax:success被触发,但是当我检查该事件的数据属性时,我看到一些奇怪的东西。它似乎是Turbolinks即将要做或刚刚完成的文本表示(?!)。Turbolinks.clearCache() Turbolinks.visit("http://localhost:3000/articles", {"action":"replace"})

显然我做错了,有人能否请解释一下我应该如何做?即不仅是如何使其工作,而且还要以惯用的RoR方式实现?


#编辑 我发现了罪魁祸首是片段B,因为format.html在format.json之前运行。只需交换这两个就可以解决问题:

修订后的片段A:

<!-- Default delete -> format.html -->
<td><%= link_to 'Destroy default', 
        article_path(article),
        method: :delete,
        :class=> 'remove-article' %></td>
<!-- aSync delete -> format.json -->
<td><%= link_to 'Destroy aSync', 
        article_path(article),
        method: :delete,
        remote: true,
        data: {turbolinks: false},
        :class=> 'remove-article' %></td>

修改后的代码片段 B:
def destroy  
    @article = Article.find(params[:id])

    respond_to do |format|
      if @article.destroy
        # Must place json before html, otherwise html will be executed
        format.json { render json: @article }
        format.html { redirect_to articles_path }
      else
        format.json { render json: @article.errors, status: :unprocessable_entity }
        format.html { render action: "index" }
      end
    end
 
end
2个回答

3

个人而言,我会采用不同的方法。

视图: 触发 AJAX 调用以删除文章

<td><%= link_to 'Destroy default', article, method: :delete, :remote => true, :class=> 'remove-article' %></td>

控制器:

def destroy
    @article.destroy
    respond_to do |format|
        format.js
    end
end

这将处理destroy方法并返回javascript,默认情况下,它将在相关目录中返回destroy.js.erb文件。

destroy.js.erb:

$("#article").slideToggle(300, function(){

    $("#article").remove();

});

FYI:请参考http://api.jquery.com/slidetoggle/了解更多信息。
希望这能在一定程度上帮到你。

谢谢Brad,文件destroy.js.erb在哪里?在\views\articles文件夹中吗? - Hendrik
抱歉,我刚刚注意到我在链接中漏掉了:remote => true这一部分,我会编辑答案。 - Brad
谢谢Brad。我是Rails的新手,将js文件放在视图文件夹中似乎不是一个好主意,但经过一些搜索,这似乎是处理事情的“Rails方式”。我会将您的答案标记为正确的。 - Hendrik
谢谢,我相信这里的惯例是这个js文件与特定视图直接相关,没有其他关系。如果它是一个通用函数,那么将函数添加到资产管道中,并使用.js.erb调用该函数。很高兴你解决了问题。 - Brad

0

尝试修改您的代码片段A,并使用no_turbolink: true

代码片段A

<td data-no-turbolink="true"><%= link_to 'Destroy', 
        article_path(article),
        method: :delete,
        data: {no_turbolink: true, remote: true},
        :class=> 'remove-article' %></td>

生成的链接 HTML 应包含以下代码:

data-no-turbolink="true"

编辑:在标签中添加data-no-turbolink="true",希望能有所帮助,你的问题根源是禁用了turbolink,一旦我们解决它,我认为你应该没问题了。

退出Turbolink


我尝试了这个,结果HTML现在看起来像这样:<a data-no-turbolink="true" data-remote="true" class="remove-article" rel="nofollow" data-method="delete" href="/articles/38">Destroy</a>。不幸的是,这并没有改变任何东西。 - Hendrik
@Hendrik编辑后,在td标签中添加了data-no-turbolink="true",请尝试一下。 - IKA
好的,现在已添加到<td>中,但仍没有运气。 <td data-no-turbolink="true"><a data-no-turbolink="true" data-remote="true" class="remove-article" rel="nofollow" data-method="delete" href="/articles/41">销毁</a></td> - Hendrik
感谢您分享您认为我问题的根源是什么。我也怀疑是同样的问题。但目前这些 turbolinks 看起来非常顽固。一位同事建议完全退出 turbolinks,但我认为这将是一件遗憾的事情,因为它们在页面转换等方面确实非常好用。 - Hendrik
@Hendrik 我知道我们需要集中精力解决手头的问题,所以我真的无法理解为什么在你的情况下Turbolinks会如此持久。总的来说,实际上朝着你的同事提到的方向前进可能是值得的。另外,有关如何禁用特定元素的turbolinks存在差异,一些来源称data-no-turbolink="true",但其他人则提到data-turbolinks="false"。还要注意一个情况中是单数,而在第二个情况中是复数。我会尝试所有组合,看看它们是否有任何帮助。例如:no_turbolinks: true turbolink: false等等。 - IKA
谢谢你的帮助...我开始觉得完全退出Turbolinks可能更好。文档似乎不准确,例如:此外,Turbolinks被安装为链接的最后一个单击处理程序。因此,如果您安装了另一个处理程序,该处理程序调用event.preventDefault(),那么Turbolinks将不会运行。 我尝试了这个,但也没有起作用。 - Hendrik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接