Roland Tony
Roland Tony

Reputation: 11

Like/Dislike on Ruby on Rails with AJAX

I am new to Ruby on Rails and I am working on a project (Pinterest clone) which has a model User and a model Pin. I am using the acts_as_votable gem for users to upvote or downvote images uploaded which I call 'pins'. Everything is working well but I am refreshing the page for the like/dislike system to make an update to the likes/dislikes counter.

I would like to use AJAX so that I don't need to refresh the page.

The Pin controller has this:

def destroy
    @pin.destroy
    redirect_to root_path   
end

def  upvote
    @pin.upvote_by current_user
    redirect_to :back
end

def downvote
    @pin.downvote_by current_user
    redirect_to :back
end

private

def pin_params
    params.require(:pin).permit(:title, :description, :image) 
end

def find_pin
    @pin = Pin.find(params[:id])
end

I am using haml, and the Pin -> show view has the following:

#pin_show.row
 .col-md-8.col-md-offset-2
    .panel.panel-default
        .panel-heading.pin_image
            = image_tag @pin.image.url
        .panel-body
            %h1= @pin.title
            %p.description= @pin.description
        .panel-footer
            .row
                .col-md-6
                    %p.user
                        Submitted by
                        = @pin.user.name
                .col-md-6
                    .btn-group.pull-right
                        = link_to like_pin_path(@pin), method: :put, class: "btn btn-default" do
                            %span.glyphicon.glyphicon-heart-empty
                                = @pin.get_upvotes.size

                        = link_to dislike_pin_path(@pin), method: :put, class: "btn btn-default" do
                            %span.glyphicon.glyphicon-thumbs-down   
                                = @pin.get_downvotes.size   
                        - if @pin.user == current_user      
                            = link_to "Edit", edit_pin_path, class: "btn btn-default"
                            = link_to "Delete", pin_path, method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-default"

And my routes.rb has this:

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

end

How do I implement AJAX when I have this approach. I am new to rails and I am pretty much stuck here

Upvotes: 1

Views: 994

Answers (1)

evanbikes
evanbikes

Reputation: 4171

Rails' unobtrusive Javascript will listen to links with data-remote=true and submit those as js requests.

= link_to like_pin_path(@pin), method: :put, data: { remote: true }...

These requests will come in to your controller as format js, so your controller actions don't need to redirect if it's format js.

def  upvote
  @pin.upvote_by current_user
  respond_to do |format|
    format.html { redirect_to :back }
    format.js { render 'vote' }
  end
end

That will upvote the @pin for you. But if you want to show feedback on the click, you'll need some js. You could have the upvote method render a js template that re-renders the template:

views/pins/vote.js.erb

$(function() { 
  $('span.glyphicon.glyphicon-heart-empty').text("<%= @pin.get_upvotes.size %>");
  $('span.glyphicon.glyphicon-thumbs-down').text("<%= @pin.get_downvotes.size %>");
});

EDIT: Debugging

If the Javascript isn't doing what you expect, there are a few ways to figure out what's wrong.

vote.js.erb

$(function() { 
  var upvotes = "<%= @pin.get_upvotes.size %>";
  var downvotes = "<%= @pin.get_downvotes.size %>"
  debugger;
});

If you have the Javascript console open, the debugger will pause execution and allow you to insert the jQuery manually. You'll have access to upvotes and downvotes and you can paste in $('.glyphicon-heart-empty') and make sure that finds the right element.

Upvotes: 1

Related Questions