Rails upvote/downvote 使用 Ajax 和 acts_as_votable
Rails upvote/downvote using Ajax and acts_as_votable
对 Rails 还是很陌生。我使用 acts_as_votable gem 创建赞成票和赞成票按钮以允许用户 upvote/downvote 笑话,但我不能让他们从赞成票/反对票(反之亦然)和更新每次他们点击而不刷新页面时都会进行计数。我尝试了其他类似的答案但没有运气。这是我试图实现的。
笑话模型
acts_as_votable
用户模型
acts_as voter
Routes.rb 是
resources :jokes do
member do
get "like" => "jokes#upvote"
get "unlike" => "jokes#downvote"
end
end
笑话控制器是
#upvote from user
def upvote
@joke = Joke.find(params[:id])
@joke.upvote_from current_user
respond_to do |format|
format.html { redirect_to :back }
format.js { render :layout => false }
end
end
#downvote from user
def downvote
@joke = Joke.find(params[:id])
@joke.downvote_from current_user
respond_to do |format|
format.html { redirect_to :back }
format.js { render :layout => false }
end
end
我的看法:
<div class="votes">
<%= link_to like_joke_path(@joke), method: :get, remote: true, class: 'like_joke' do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-up"></i>
<span class="badge vote_count"><%= @joke.get_upvotes.size %></span>
</button>
<% end %>
<%= link_to unlike_joke_path(@joke), method: :get, remote: true, class: 'unlike_joke' do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-down"></i>
<span class="badge voute_count"><%= @joke.get_downvotes.size %></span>
</button>
<% end %>
</div>
like.js.erb:
$('.like_joke').bind('ajax:success', function(){
$(this).parent().parent().find('.vote_count').html('<%= escape_javascript @joke.votes_for.size.to_s %>');
$(this).closest('.like_joke').hide();
$(this).closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: 'unlike_joke' %>');
});
最后取消like.js.erb:
$('.unlike_joke').bind('ajax:success', function(){
$(this).parent().parent().find('.vote_count').html('<%= escape_javascript @joke.votes_for.size.to_s %>');
$(this).closest('.unlike_joke').hide();
$(this).closest('.votes').html(' <%= link_to "Like", like_joke_path(@joke), remote: true, method: :get, class: 'like_joke' %>');
});
这是渲染后的 HTML:
<div class="votes">
<a class="like_joke" data-remote="true" data-method="get" href="/jokes/11-cat-joke-title/like">
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-up"></i>
<span class="badge vote_count">0</span>
</button>
</a>
<a class="unlike_joke" data-remote="true" data-method="get" href="/jokes/11-cat-joke-title/unlike">
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-down"></i>
<span class="badge voute_count">1</span>
</button>
</a></div>
当我查看 js 控制台时,我在 jquery.js?body=1:9665 处收到内部服务器错误,即 xhr.send( ( options.hasContent && options.data ) || null );
看起来我很接近,但我想我在我的观点和 js 中搞砸了一些东西。有人可以告诉我我缺少什么吗?
如果您查看您提供的代码...该代码为字符串内部和外部的内容着色...您会在此处注意到这一行:
$(this).closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: 'unlike_joke' %>');
着色以便部分代码在字符串内...但部分不在(向右滚动查看它,它接近尾声)。
我不确定这是不是你的错误,但你可能应该考虑将其更改为:
$(this).closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: "unlike_joke" %>');
如果只是为了消除歧义。 (同时检查其他行是否存在类似问题)
好的,我认为问题是这样的。
一旦你点击了喜欢......你就会去喜欢的动作(顺便说一句,为了保持一致性,你应该调用 'like' 而不是 'upvote')>
然后渲染 like.js.
此时您希望 js 实际更新 like-count 等。
您已经拥有 javascript,并且只想立即 运行。
您不需要将其绑定到 ajax 成功...您已经成功了。所以你的 like.js 应该只包含裸 javascript 来实际更新屏幕,例如:
var like_joke = $('.unlike_joke');
like_joke.parent().parent().find('.vote_count').html('<%= escape_javascript @joke.votes_for.size.to_s %>');
like_joke.closest('.like_joke').hide();
like_joke.closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: 'unlike_joke' %>');
注意:未经测试,可能存在错误,但您明白了。不要放置将在 ajax 成功时调用的函数,否则它将坐在那里等待其他成功发生。成功已经发生了......现在去做吧:)
另请注意:此处有错别字:
<span class="badge voute_count"><%= @joke.get_downvotes.size %></span>
应该是
<span class="badge vote_count"><%= @joke.get_downvotes.size %></span>
更好的方法...
#config/routes.rb
resources :jokes do
match :vote, via: [:post, :delete], on: :member
end
#app/controllers/jokes_controller.rb
class JokesController < ApplicationController
def vote
@joke = Joke.find(params[:id])
if request.post?
@joke.upvote_from current_user
elsif request.delete?
@joke.downvote_from current_user
end
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
end
创建单个 partial
视图:
#app/views/jokes/_vote.html.erb
<% voted = current_user.voted_for? joke %>
<% styling = voted ? "" : "un" %>
<% arrow = voted ? "up" : "down" %>
<% method = voted ? :delete : :post %>
<%= link_to vote_joke_path(joke), method: method, remote: true, class: '#{styling}like_joke', id: joke.id do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-<%= arrow %>"></i>
<span class="badge vote_count"><%= joke.get_upvotes.size %></span>
</button>
<% end %>
#app/views/jokes/show.html.erb
<%= render partial: "vote", locals: { joke: @joke } %>
这样,当您从 JokesController
调用 vote.js.erb
时,您将能够使用以下内容:
#app/views/jokes/vote.js.erb
$("<%=j @joke.id %>").html("<%=j render partial: "jokes/vote", locals: { joke: @joke } %>");
对 Rails 还是很陌生。我使用 acts_as_votable gem 创建赞成票和赞成票按钮以允许用户 upvote/downvote 笑话,但我不能让他们从赞成票/反对票(反之亦然)和更新每次他们点击而不刷新页面时都会进行计数。我尝试了其他类似的答案但没有运气。这是我试图实现的。
笑话模型
acts_as_votable
用户模型
acts_as voter
Routes.rb 是
resources :jokes do
member do
get "like" => "jokes#upvote"
get "unlike" => "jokes#downvote"
end
end
笑话控制器是
#upvote from user
def upvote
@joke = Joke.find(params[:id])
@joke.upvote_from current_user
respond_to do |format|
format.html { redirect_to :back }
format.js { render :layout => false }
end
end
#downvote from user
def downvote
@joke = Joke.find(params[:id])
@joke.downvote_from current_user
respond_to do |format|
format.html { redirect_to :back }
format.js { render :layout => false }
end
end
我的看法:
<div class="votes">
<%= link_to like_joke_path(@joke), method: :get, remote: true, class: 'like_joke' do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-up"></i>
<span class="badge vote_count"><%= @joke.get_upvotes.size %></span>
</button>
<% end %>
<%= link_to unlike_joke_path(@joke), method: :get, remote: true, class: 'unlike_joke' do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-down"></i>
<span class="badge voute_count"><%= @joke.get_downvotes.size %></span>
</button>
<% end %>
</div>
like.js.erb:
$('.like_joke').bind('ajax:success', function(){
$(this).parent().parent().find('.vote_count').html('<%= escape_javascript @joke.votes_for.size.to_s %>');
$(this).closest('.like_joke').hide();
$(this).closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: 'unlike_joke' %>');
});
最后取消like.js.erb:
$('.unlike_joke').bind('ajax:success', function(){
$(this).parent().parent().find('.vote_count').html('<%= escape_javascript @joke.votes_for.size.to_s %>');
$(this).closest('.unlike_joke').hide();
$(this).closest('.votes').html(' <%= link_to "Like", like_joke_path(@joke), remote: true, method: :get, class: 'like_joke' %>');
});
这是渲染后的 HTML:
<div class="votes">
<a class="like_joke" data-remote="true" data-method="get" href="/jokes/11-cat-joke-title/like">
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-up"></i>
<span class="badge vote_count">0</span>
</button>
</a>
<a class="unlike_joke" data-remote="true" data-method="get" href="/jokes/11-cat-joke-title/unlike">
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-down"></i>
<span class="badge voute_count">1</span>
</button>
</a></div>
当我查看 js 控制台时,我在 jquery.js?body=1:9665 处收到内部服务器错误,即 xhr.send( ( options.hasContent && options.data ) || null );
看起来我很接近,但我想我在我的观点和 js 中搞砸了一些东西。有人可以告诉我我缺少什么吗?
如果您查看您提供的代码...该代码为字符串内部和外部的内容着色...您会在此处注意到这一行:
$(this).closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: 'unlike_joke' %>');
着色以便部分代码在字符串内...但部分不在(向右滚动查看它,它接近尾声)。
我不确定这是不是你的错误,但你可能应该考虑将其更改为:
$(this).closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: "unlike_joke" %>');
如果只是为了消除歧义。 (同时检查其他行是否存在类似问题)
好的,我认为问题是这样的。 一旦你点击了喜欢......你就会去喜欢的动作(顺便说一句,为了保持一致性,你应该调用 'like' 而不是 'upvote')> 然后渲染 like.js.
此时您希望 js 实际更新 like-count 等。 您已经拥有 javascript,并且只想立即 运行。 您不需要将其绑定到 ajax 成功...您已经成功了。所以你的 like.js 应该只包含裸 javascript 来实际更新屏幕,例如:
var like_joke = $('.unlike_joke');
like_joke.parent().parent().find('.vote_count').html('<%= escape_javascript @joke.votes_for.size.to_s %>');
like_joke.closest('.like_joke').hide();
like_joke.closest('.votes').html(' <%= link_to "Unlike", unlike_joke_path(@joke), remote: true, method: :get, class: 'unlike_joke' %>');
注意:未经测试,可能存在错误,但您明白了。不要放置将在 ajax 成功时调用的函数,否则它将坐在那里等待其他成功发生。成功已经发生了......现在去做吧:)
另请注意:此处有错别字:
<span class="badge voute_count"><%= @joke.get_downvotes.size %></span>
应该是
<span class="badge vote_count"><%= @joke.get_downvotes.size %></span>
更好的方法...
#config/routes.rb
resources :jokes do
match :vote, via: [:post, :delete], on: :member
end
#app/controllers/jokes_controller.rb
class JokesController < ApplicationController
def vote
@joke = Joke.find(params[:id])
if request.post?
@joke.upvote_from current_user
elsif request.delete?
@joke.downvote_from current_user
end
respond_to do |format|
format.html { redirect_to :back }
format.js
end
end
end
创建单个 partial
视图:
#app/views/jokes/_vote.html.erb
<% voted = current_user.voted_for? joke %>
<% styling = voted ? "" : "un" %>
<% arrow = voted ? "up" : "down" %>
<% method = voted ? :delete : :post %>
<%= link_to vote_joke_path(joke), method: method, remote: true, class: '#{styling}like_joke', id: joke.id do %>
<button type="button" class="btn btn-info" aria-label="Left Align">
<i class="fa fa-arrow-<%= arrow %>"></i>
<span class="badge vote_count"><%= joke.get_upvotes.size %></span>
</button>
<% end %>
#app/views/jokes/show.html.erb
<%= render partial: "vote", locals: { joke: @joke } %>
这样,当您从 JokesController
调用 vote.js.erb
时,您将能够使用以下内容:
#app/views/jokes/vote.js.erb
$("<%=j @joke.id %>").html("<%=j render partial: "jokes/vote", locals: { joke: @joke } %>");