Reputation: 11
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
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