Ajax:success 无法在 rails 应用中运行

Ajax:success not working in rails app

在 rails 4 应用程序中,我使用 link_to 通过 json 发送对帖子的赞成票。

这是我的帖子控制器中的内容:

def upvote
  @post = Post.find(params[:id])
  @post.liked_by current_user

    respond_to do |format|
    format.html {redirect_to :back }
    format.json { render json: { count: @post.get_upvotes.size } }
  end
end

这是我的看法

<%= link_to like_post_path(post), method: :put, class: 'vote', remote: true, data: { type: :json } do %>
    <%= image_tag('vote.png') %>
    <%= content_tag :span, post.get_upvotes.size %>
    <% end %>


    <script>

    $(document)
        .on('ajax:send', '.vote', function () { $(this).addClass('loading'); })
        .on('ajax:complete', '.vote', function () { $(this).removeClass('loading'); })
        .on('ajax:error', '.vote', function(e, xhr, status, error) { console.log(status); console.log(error); })
        .on('ajax:success', '.vote', function (e, data, status, xhr) {
        $(this).find("span").html(data.count);
        $(this).find("img").attr("src", '<%= asset_path 'voted.png' %>'); 
        });


    </script>

当我点击 link 时,投票作为 JSON 请求进行,我在我的日志中看到:

Processing by PostsController#upvote as JSON

但由于某种原因,我的 javascript 片段无法正常工作。计数器或图标都不会更新。 我该如何解决这个问题?这是否与 turbolinks 有关,是否与我放置 javascript 的位置有关?

jQuery 是默认的 rails javascript 库。默认的 rails javascript 库曾经是 prototype,所以旧 tutorials/docs 使用它。这就是 ajax 和 jQuery 的样子:

app/controllers/static_pages_controller.rb:

class StaticPagesController < ApplicationController

  def show_link
  end

  def upvote
    respond_to do |format|
      format.json {render json: {"count" => "10"} }
    end
  end

end

app/views/static_pages/show_link.html:

<div>Here is an ajax link:</div>

<%= link_to(
    "Click me", 
    '/static_pages/upvote', 
    'remote' => true,  #Submit request with ajax, and put text/javascript on front of Accept header
    data: { type: :json })  #Put application/json on front of Accept header
%>


<div>Upvotes:</div>
<div id="upvotes">3</div>

<script>
$(document).ready( function() {

  $(this).ajaxSuccess( function(event, jqXHR, ajaxInfo, data) {

    //var js_obj = JSON.parse(jqXHR.responseText);
    //$('#upvotes').html(js_obj["count"]);

    //Apparently, the fourth argument to the handler, data,
    //already contains the js_obj created from parsing the  
    //json string contained in the response. 

    $('#upvotes').html(data["count"]);
  });

}); 
</script>

config/routes.rb:

Test1::Application.routes.draw do

  get 'static_pages/show_link'
  get 'static_pages/upvote'
  ...
end

url 在浏览器中输入:

http://localhost:3000/static_pages/show_link

在此处查看 jquery 文档:

http://api.jquery.com/ajaxSuccess/

回复评论:

您还可以在控制器中执行以下操作:

  def upvote

    @upvotes = 2  #Set an @variable to the number of upvotes

    respond_to do |format|
      format.js {}  #By default renders app/views/static_pages/upvote.js.erb
    end

  end

然后:

app/views/static_pages/upvote.js.erb:

$('#upvotes').html(<%= @upvotes %>)

在 Rails 中,您可以通过 JavaScript 响应来执行类似的任务。在你的 respond_to 中添加一个类似于 format.htmlformat.js 然后有一个视图 upvote.js.erb 看起来像:

(function() {    

var postId = "#post-<%= @post.id %>";

$(postId).find(".vote").find("span").text("<%= @post.get_upvotes.size %>");
$(postId).find(".vote").find("img").attr("src", "<%= asset_path "voted.png" %>");

})();

我将您对 .html 的调用更改为 .text,因为您实际上并未在元素内设置任何 HTML,因此没有理由调用 .html

这个 post 还假设有某种机制可以识别 post 投票 link 所属的(在示例中,父 post 元素的 ID 为"post-#" 其中 # 是 post 对象的 ID)。

编辑

如果我从事这个项目,我会做出两个改变。首先,我会将 voted.png 路径作为数据属性附加到 .vote 元素。 data-voted-image-src="<%= asset_path "voted.png" %>"。接下来,我永远不会在 return 中传递数字,因为没有理由这样做。单击投票后,假设请求成功,您可以在前端处理所有事情。这节省了所有这些潜在的麻烦。虽然我意识到从当前必须更改为添加数据属性并不是一个巨大的飞跃,但我发现它比在 JavaScript.

中具有更多语义。

投票的点击动作link则变为:

// Assume all posts have a class 'post'
// I'm also using 'one' because once they vote they don't need to anymore
$(".post").find(".vote").one("click", function(e) {
  var count = parseInt($(this).find("span").text()),
      votedSrc = $(this).data("voted-image-src");
  $(this).find("img").attr("src", votedSrc);
  $(this).find("span").text(count + 1);
});

现在不需要服务器的响应,您可以将 JSON 响应更改为 {success: true} 或其他简单的响应。