【问题标题】:AJAX Render PartialAJAX 渲染部分
【发布时间】:2014-06-14 06:00:29
【问题描述】:

我正在尝试完成我认为最直接但肯定不是最优雅的 reddit 风格投票按钮的复制。我的代码可以在没有 AJAX 的情况下工作,但我希望用户能够单击投票按钮,并且他们可以在不重新加载页面的情况下进行适当的更改(因此是 AJAX)。

当我尝试删除单击的投票按钮并替换为适当的“突出显示”投票按钮时,会出现问题。我替换投票按钮的原因是因为我需要将其更改为单击后将取消投票的按钮。

(我已将其简化为仅处理 upvoting,因为 downvoting 是相同的 mechhanic)。这是我的观点

  <% @posts.each do |post| %>
    <%= post.content %>
    <% if current_user.voted_as_when_voted_for post %>
      <%= render 'upvoted', post: post %>
    <% else %>
      <%= render 'upvote', post: post %>
    <% end %>
  <% end %>

如果他们对帖子投了赞成票,则 voted_as_when_voted_for 方法返回 true。 以下是点赞和点赞的表单

<%= link_to image_tag('upvoted.png', size: '18'), remove_like_post_path(post), method: :put, remote: true, id: "upvoted#{post.id}" %>

<%= link_to image_tag('upvote.png', size: '18'), like_post_path(post), method: :put, remote: true, id: "upvote#{post.id}" %>

这是我的控制器:

def upvote
  @post = Post.find(params[:id])
  @post.liked_by current_user
  respond_to do |format|
    format.html { redirect_to @post.parent }
    format.js   {}
  end
end

def remove_upvote
  @post = Post.find(params[:id])
  @post.unliked_by current_user
  respond_to do |format|
    format.html { redirect_to @post.parent }
    format.js   {}
  end
end

upvote.js.erb:upvoted.js.erb:

$('#upvote<%= @post.id %>').remove().append('<%= j render("upvoted") %>');

$('#upvoted<%= @post.id %>').remove().append('<%= j render("upvote") %>');

使用这些文件,我得到以下控制台错误:

PUT http://localhost:3000/posts/96/like 500 (Internal Server Error) 

NameError in Posts#upvote

undefined local variable or method `post' for #<#<Class:0x007fde1836cbf0>:0x007fde18c00af0>

_upvote.html.erb_upvoted.html.erb

<%= link_to image_tag('upvote.png', size: '18'), like_post_path(post), method: :put, remote: true, id: "upvote#{post.id}" %>

<%= link_to image_tag('upvoted.png', size: '18'), like_post_path(post), method: :put, remote: true, id: "upvoted#{post.id}" %>

我也根据以下链接尝试了类似的方法:

$('#upvote<%= @post.id %>').remove().after('<%= j render "upvoted", post: @post %>');

当我使用该代码时,upvote 已成功删除,但未添加 upvote 表单。所以看来我需要使用实例变量,但有些东西仍然不太有效。

我错过了什么??

这个人好像也有类似的问题:Rails Ajax Render Partial

【问题讨论】:

  • 开发者控制台有错误吗?您可以在 js.erb 文件中发出警报吗?
  • 我在控制台日志中添加了生成错误的代码。我是 Rails 新手,对这些日志不是很有经验,所以如果您想从它们那里看到更多内容,请告诉我。
  • 尝试 $('#upvote').remove().after('');
  • 这里可能还有其他问题,但对于 javascript,您在匹配的元素上调用 .remove()。然后尝试append 到一个不再存在的元素。
  • @veritas1,没错,而是我先附加,然后删除链接。

标签: ruby-on-rails ajax ruby-on-rails-4


【解决方案1】:

干燥

在我看来不是很干燥

您可以通过更好地利用 HTTP Verbs 来删除大量重复代码 - 通过定义 delete 路由(用于支持投票)和 post 路由(用于支持投票):

#config/routes.rb
resources :posts do
   match :vote, via: [:post, :delete] #-> domain.com/posts/14/vote
end

#app/controllers/posts_controller.rb
Class PostsController < ActiveRecord::Base
    respond_to :js, :html
    def vote
       @post = Post.find params[:id]

       if request.post? 
          @post.liked_by current_user
       elsif request.delete?
          @post.unliked_by current_user
       end

       respond_with @post
    end
end

观看次数

这将允许您创建以下 JS 和视图:

#app/views/posts/vote.js.erb
$("<%= 'upvote##{@post.id}' %>").html('<%= j render "vote", locals: { post: @post } %>');

-

#app/views/posts/_vote.html.erb
image = current_user.voted_as_when_voted_for(post) ? "downvote.png" : "upvote.png"
method = current_user.voted_as_when_voted_for(post) ? :delete : :post

<%= link_to image_tag(image, size: '18'), post_vote_path(post), method: method, remote: true, id: "upvote#{post.id}" %>

-

#app/views/posts/show.html.erb
<% @posts.each do |post| %>
    <%= post.content %>
    <%= render 'vote', post: post %>
<% end %>

修复

查看您的代码后,我会查看错误以获取有关问题可能是什么的提示:

未定义的局部变量或方法`post'

问题似乎是在您的upvote 操作中调用的,它的partial upvoted 如下所示:

$('#upvoted<%= @post.id %>').remove().append('<%= j render("upvote") %>');

问题是这个部分需要post 局部变量。所以问题是你没有通过locals 参数将@post 传递给你的partial

我上面的代码解决了这个问题,但为了解决它,你应该使用locals: { post: @post }

【讨论】:

    【解决方案2】:

    好的,所以 ajax 失败的真正罪魁祸首是使用.remove().after 我的理论是,如果我删除了元素,那么你就不能再添加一些东西了。所以这个修复解决了这个问题:

    $('#upvote<%= @post.id %>').after('<%= j render "upvoted", post: @post %>');
    $('#upvote<%= @post.id %>').remove();
    

    也许不是最复杂的,但它确实有效!注意:我不想使用.hide().after(),因为我不希望后面有很多隐藏的链接。

    【讨论】:

      猜你喜欢
      • 2012-01-17
      • 1970-01-01
      • 1970-01-01
      • 2013-01-29
      • 1970-01-01
      • 2015-04-30
      • 1970-01-01
      • 2022-08-19
      相关资源
      最近更新 更多