Ruby on Rails防止Turbolink劫持AJAX操作

Hen*_*rik 5 ajax ruby-on-rails turbolinks

我遵循RoR入门指南,并在进行过程中添加了一些内容。具体来说,我要实现的是在步骤5.13删除文章中,我使用AJAX而不是标准模式来删除文章。

我想以最适合RoR的做事方式来做。在阅读了在Rails中使用JavaScript一章之后,似乎可以采取以下步骤:

  1. remote: truelink_to助手添加属性(请参见代码段A)
  2. link_to通过添加禁用涡轮增压器此帮助程序data: {turbolinks: false}(请参见代码段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>
Run Code Online (Sandbox Code Playgroud)

片段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
Run Code Online (Sandbox Code Playgroud)

片段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);
    });
  }
})();
Run Code Online (Sandbox Code Playgroud)

这不太符合我的预期:

  • 禁用turbolinks无效:它仍在替换整个页面内容。
  • 事件ajax:success事件被触发,但是当我检查该事件的数据属性时,我看到了一些奇怪的东西。似乎是Turbolink即将完成/刚刚完成(?!)的文字表示。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>
Run Code Online (Sandbox Code Playgroud)

修改后的摘要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
Run Code Online (Sandbox Code Playgroud)

Bra*_*rad 3

我个人会以不同的方式看待这个问题。

View:触发ajax调用删除文章

<td><%= link_to 'Destroy default', article, method: :delete, :remote => true, :class=> 'remove-article' %></td>
Run Code Online (Sandbox Code Playgroud)

控制器:

def destroy
    @article.destroy
    respond_to do |format|
        format.js
    end
end
Run Code Online (Sandbox Code Playgroud)

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

destroy.js.erb:

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

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

});
Run Code Online (Sandbox Code Playgroud)

仅供参考: http: //api.jquery.com/slidetoggle/

希望这会有所帮助