Rails使用Ajax和acts_as_votable进行upvote / downvote

时间:2016-01-13 03:05:50

标签: javascript ruby-on-rails ruby ajax acts-as-votable

Rails还是比较新的。我使用acts_as_votable gem来创建upvote和upvote按钮以允许用户上调/下调笑话,但是我不能让它们从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' %>');
});

最后不像.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&amp;&amp; options.data)|| null);

好像我很接近,但我认为我的观点和js搞砸了。有人能告诉我我缺少的东西吗?

2 个答案:

答案 0 :(得分:1)

如果你看一下你提供的代码......代码就是字符串内部和外部的颜色......你会注意到这一行:

 $(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" %>');

如果只是为了消除歧义。 (还检查其他类似问题)

好的,我认为问题在于此。 一旦你点击了...你就会去喜欢的行动(顺便说一句,你应该称之为'喜欢'而不是'upvote'以保持一致性)&gt; 然后你渲染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>

答案 1 :(得分:0)

更好的方式......

#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 } %>

这样,当您从vote.js.erb调用JokesController时,您就可以使用以下内容:

#app/views/jokes/vote.js.erb
$("<%=j @joke.id %>").html("<%=j render partial: "jokes/vote", locals: { joke: @joke } %>");