我正在努力实现我认为最直接的,但肯定不是最优雅的复制reddit样式投票按钮。我的代码在没有AJAX的情况下工作,但我希望用户能够单击投票按钮并在不重新加载页面的情况下进行适当更改(因此是AJAX)。
当我尝试删除单击的投票按钮并使用相应的“突出显示”投票按钮替换时,会出现问题。我替换投票按钮的原因是因为我需要将其更改为一个按钮,如果点击该按钮将不会投票。
(我简化了这个只是为了处理upvoting,因为downvoting是相同的mexhanic)。这是我的视图:
<% @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。 这是upvote和upvoted 表单:
<%= 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,但未添加upvoted表单。所以我似乎需要使用实例变量,但有些东西仍然不能正常工作。
我错过了什么?
这个人似乎有类似的问题:Rails Ajax Render Partial
答案 0 :(得分:0)
<强> DRY 强>
对我来说看起来不太干净
您可以通过更好地使用HTTP Verbs来删除大量重复代码 - 定义delete
路由(用于downvote)&amp; post
路线(用于upvote):
#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&amp;的观点:
#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 }
答案 1 :(得分:0)
好的,所以ajax失败的真正罪魁祸首就是使用.remove().after
我的理论是,如果我删除元素,那么你就不能在之后添加一些东西了。所以这个解决方案解决了这个问题:
$('#upvote<%= @post.id %>').after('<%= j render "upvoted", post: @post %>');
$('#upvote<%= @post.id %>').remove();
也许不是最复杂的,但它的确有效!注意:我不想使用.hide().after()
,因为我不想隐藏许多隐藏的链接。