Search code examples
javascriptjqueryruby-on-railsruby-on-rails-3voting

JQuery + thumbs_up gem render vote count?


Plugins: Thumbs Up & JQuery 1.5.2 (needed for another old gem)

I'm trying to render an updated vote count w/o a full HTTP request when a user votes on a post. Currently, it refreshes the page on every vote.

Posts Controller

def vote_up
  post = Post.find(params[:id])
  current_user.vote_exclusively_for(post)
  respond_to do |format|
    format.js
    format.html {rRedirect_to :back}
  end
end

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

Vote View (each post div has a vote div on the left (digg/reddit style) and content on the right)

 <div class="post">
 <div class="vote">
 <div class="votewrapper">
  <span class="votecount">
  <%= post.votes_for - post.votes_against %>
    </span>
  <div class="votebtn">
   <%= link_to image_tag('vote.png'), vote_up_post_path(post), :method => :post, :format => :js %>
     </div>
   </div>
   </div>
   <div class="postcontent">
   all the post content, timestamp stuff, etc...
   </div>
   </div>

vote_up.erb.js (in the Posts folder).

$(".votecount").html(
"<%= escape_javascript post.votes_for - post.votes_against %>");

I've been stuck on this for a while and would very much appreciate any help ya'll can offer. I've seen the Jquery railscast and looked through other Stackoverflow answers, but I'm still quite noobish at Jquery.


Solution

  • It seems like you'll want to separate out your view code into partials and only refresh one partial when a rating is provided.

    For your controller, instead of:

    respond_to do |format|
        format.js
        format.html {redirect_to :back}
      end
    

    Do something like:

    render :partial => "voutecount"
    

    In your view, move out the votewrapper div into a new file called "_votecount.html.erb" within the same directory, and instead have the render code:

     <%= render :partial => "votecount" %>
    

    If you want to block the rating while it's refreshing (recommended), then you may want to ajaxify the call and control it more in the js. So, include your javascript within the view:

    <%= javascript_include_tag 'votecount' %>
    

    replace your link_to with good ol' html to have more info:

    <a href="" class="ratelink" updown="up" theid="123"><img src = "...."></a>
    <a href="" class="ratelink" updown="down" theid="123"><img src = "...."></a>
    

    And create a new votecount.js in your public/javascripts folder with the following content:

      $(function(){
            $(".ratelink").click(function(){
                var val = $(this).attr('updown');
                var theid = $(this).attr('theid');
                $("#votewrapper").block({ //blocks rate-rates while processing
                    message: null,
                    overlayCSS: {
                        backgroundColor: '#FFF',
                        opacity: 0.6,
                        cursor: 'default'
                    },
                });
            if (val == "up") {
            $.ajax({
                    type: 'PUT',
                    url: "/mymodel/voteup?id="+theid,
                    success: function(){
                                $("#votewrapper").unblock();
                                }   
                       });
            } else {
                 $.ajax({
                    type: 'PUT',
                    url: "/mymodel/votedown?id="+theid,
                    success: function(){
                                $("#votewrapper").unblock();
                                }   
                       });
            }
        })
    

    good luck! :)