javascriptruby-on-railsrubyajaxacts-as-votable

Ajax for post upvote/downvote (stopping page refresh)


I'm using "acts_as_votable" gem in my Rails application so that Users can vote on Posts. I'm trying to add Ajax functionality so that the entire page doesn't have to refresh when a user upvotes a post.

My upvote/downvote links are clickable and record the votes, but the render is not refreshing and the vote count still remains the same (I still have to refresh the page to see the count change).

I can see my in Run log this error:

Rendered posts/downvote.js.erb (3.4ms)
Completed 500 Internal Server Error in 77ms (ActiveRecord: 8.4ms)

ActionView::Template::Error (undefined method `id' for nil:NilClass):
    1: $(document).ready(function(){
    2:     $('#vote_<%= p.id %>').html("<%= escape_javascript render :partial => 'vote' %>");
    3: });
  app/views/posts/downvote.js.erb:2:in `_app_views_posts_downvote_js_erb__811382410496335987_70314739481440'
  app/controllers/posts_controller.rb:44:in `downvote'


  Rendered /usr/local/rvm/gems/ruby-2.3.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb (1.0ms)
  Rendered /usr/local/rvm/gems/ruby-2.3.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb (0.7ms)
  Rendered /usr/local/rvm/gems/ruby-2.3.0/gems/actionpack-4.2.5/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb (17.0ms)

Here is what I have:

routes.rb

  resources :posts do 
    member do
      put "like", to: "posts#upvote"
      put "dislike", to: "posts#downvote"
    end
  end

posts_controller.rb

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

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

explore.html.erb (/views/pages/explore.html.erb)

<% if @posts.each do |p| %>
<div class="panel-body">
  <p class="post-content"><%= auto_link(p.content, :html => { :target => '_blank' }) %></p>

  <%= render :partial => '/posts/vote', :class => "vote", :locals => { p: p } %>

</div>
<% end %>

_vote.html.erb (/views/posts/_vote.html.erb)

<<div id="vote_<%= p.id %>" class="vote">
  <%= link_to 'Vote Up', like_post_path(p), :class => "upvote", :method => :put, :remote => true %>
  <span><%= p.score %></span>  <!--show the current vote-->
  <%= link_to 'Vote Down', dislike_post_path(p), :class => "downvote", :method => :put, :remote => true %>
</div>

upvote.js.erb (/views/posts/upvote.js.erb)

$(document).ready(function(){
    $('#vote_<%= p.id %>').html("<%= escape_javascript render :partial => 'vote' %>");
});

downvote.js.erb (/views/posts/downvote.js.erb)

$(document).ready(function(){
    $('#vote_<%= p.id %>').html("<%= escape_javascript render :partial => 'vote' %>");
});

Is there something wrong with my javascript, or am I rendering something wrong? Thank you in advance.


Solution

    1. _vote.html.erb (/views/posts/_vote.html.erb) "<<" in the first line will rise an syntax error.

    2. In your *.js.erb files just have @post from controller's action, not p like in your view. Try update like below:

    upvote.js.erb (/views/posts/upvote.js.erb)

    $(document).ready(function(){
      $('#vote_<%= @post.id %>').html("<%= escape_javascript render :partial => 'vote', locals: { p: @post } %>");
    });
    

    downvote.js.erb (/views/posts/downvote.js.erb)

    $(document).ready(function(){
      $('#vote_<%= @post.id %>').html("<%= escape_javascript render :partial => 'vote', locals: { p: @post } %>");
    });
    

    Hope this help. :)