2

I'm able to click on the link once, and the count will update, but it doesn't update on the clicks after that, nor does it update into the database (looking at the console).

index.html.haml

.votes
  - if current_user.liked? skit
    = link_to unlike_skit_path(skit), method: :get, remote: true, class: "unlike-post" do
      .upvote
        %span.upvote-link
          %i.fa.fa-caret-up
        .vote-count= skit.votes_for.size
  - else
    = link_to like_skit_path(skit), method: :get, remote: true, class: "like-post" do
      .upvote
        %span.upvote-link
          %i.fa.fa-caret-up
        .vote-count= skit.votes_for.size

routes.rb

resources :skits do
  resources :challenges
  member do 
    get "like", to: "skits#like"
    get "unlike", to: "skits#unlike"
  end
end

unlike.js.erb

$('.unlike-post').bind('ajax:success', function(){
  $(this).find('.vote-count').html('<%= escape_javascript @skit.votes_for.size.to_s %>');
});

like.js.erb

$('.like-post').bind('ajax:success', function(){
  $(this).find('.vote-count').html('<%= escape_javascript @skit.votes_for.size.to_s %>');
});

skits_controller.rb

def like
  @skit.liked_by current_user
  respond_to do |format|
    format.html { redirect_to skits_path, notice: 'Successfully voted!' }
    format.js { render layout: false }
  end
end

def unlike
  @skit.unliked_by current_user
  respond_to do |format|
    format.html { redirect_to skits_path, notice: 'Successfully voted!' }
    format.js { render layout: false }
  end
end

EDIT

After applying help from bottom, doesn't save into database:

enter image description here

When it saves into database:

enter image description here

hellomello
  • 8,219
  • 39
  • 151
  • 297
  • 1
    Don't use a `GET` request to create or destroy a resource. GET requests are saved in the browser history. Instead use something like `POST /skits/1/likes` to create a like and `DELETE /likes/:id` to unlike. – max Jan 27 '16 at 08:39
  • @max thank you, do you think you can post an example? Also, what about a PUT instead? – hellomello Jan 27 '16 at 08:42
  • You can use `PUT` but it is not very RESTful. Rather `PUT /skits/1/like` is more like a procedure. I don't have the time today to type up a full answer, sorry. However this is an extremely common scenario and you should be able to dig up quite a few examples online. – max Jan 27 '16 at 09:02

2 Answers2

1

To add to @max's comment, you'll want to look at DRYing up your code (using your HTTP Verbs and actions accordingly):

# config/routes.rb
resources :skits do
  resources :challenges
  match :like, via: [:post, :delete], on: :member #-> url.com/skits/:id/like
end

# app/controllers/skits_controller.rb
class SkitsController < ApplicationController
   def like
       @skit.liked_by current_user   if request.post?
       @skit.unliked_by current_user if request.delete?
       respond_to do |format|
          format.html { redirect_to skits_path, notice: 'Successfully voted!' }
          format.js #-> format.js doesn't render layout anyway
       end       
   end
end

You'll be able to use the following:

#app/views/skits/index.html.erb
<%= render @skits %>

#app/views/skits/_skit.html.erb
.votes
   - method =  current_user.liked?(skit) ? :post : :delete
   = link_to skit_like_path(skit), method: method, remote: true, id: skit.id do
      .upvote
        %span.upvote-link
          %i.fa.fa-caret-up
        .vote-count= skit.votes_for.size

Solution

In regards the problem of updating, you'll want to make sure you're updating the correct element through your js.erb:

#app/views/skits/like.js.erb
$("#<%=j @skit.id %>").find(".vote-count").html('<%=j @skit.votes_for.size.to_s %>');

You don't need to bind the above code to ajax:success -- calling format.js will run the code at the end of the request. Although this may need tweaking, it should work.

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • I had to change the `.html('<%=j` to `.html('<%=escape_javascript`, also took out the `j` in the id. However, I'm its not saving into database anymore? – hellomello Jan 27 '16 at 17:26
  • I've added screenshot of my console showing the SQL – hellomello Jan 27 '16 at 17:32
  • FYI http://api.rubyonrails.org/classes/ActionView/Helpers/JavaScriptHelper.html#method-i-j – Richard Peck Jan 27 '16 at 20:11
  • Looking at your `SQL` log, it seems to be sending the required request to the appropriate commands etc. Are you sure it's not updating the db? – Richard Peck Jan 27 '16 at 20:13
  • I've uploaded a new screen shot of the SQL when it does save into he database. There's a DELETE SQL after before the COMMIT... actually the previous screenshot was wrong. I have the actual one which doesn't show an update to the database. Let me know if its supposed to be like this too – hellomello Jan 27 '16 at 20:41
  • So, I switched the `:post : :delete` to `:delete : :post` and now it updates into database, but it only works once, it doesn't update multiple times – hellomello Jan 27 '16 at 20:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101819/discussion-between-hellomello-and-rich-peck). – hellomello Jan 27 '16 at 20:49
1

The issue here is the HTTP method you are using for this request, you use GET when you want to get information from the server, but if you want to update resources GET is not the right way.

If I were you I would use PATCH method for this:

The HTTP methods PATCH can be used to update partial resources. For instance, when you only need to update one field of the resource, PUTting a complete resource representation might be cumbersome and utilizes more bandwidth

resources :skits do
  resources :challenges
  member do 
    patch :like
    patch :unlike
  end
end

Update the method in your haml:

.votes
  - if current_user.liked? skit
    = link_to unlike_skit_path(skit), method: :patch, remote: true, class: "unlike-post" do
      .upvote
        %span.upvote-link
          %i.fa.fa-caret-up
        .vote-count= skit.votes_for.size
  - else
    = link_to like_skit_path(skit), method: :patch, remote: true, class: "like-post" do
      .upvote
        %span.upvote-link
          %i.fa.fa-caret-up
        .vote-count= skit.votes_for.size

Also make sure you are updating the right element in your js.erb, a solution for this would be to use the @skit.id

#app/views/skits/like.js.erb
$("#<%=j @skit.id %>").find(".vote-count").html('<%=j @skit.votes_for.size.to_s %>');

By the way, you do not need to use ajax:success. format.js will handle that for you

svelandiag
  • 4,231
  • 1
  • 36
  • 72
  • Do I need to change the class on the link button or something from unlike-post to like-post and vice versa? Because this works on the first click, but after that, it doesn't update anymore – hellomello Jan 27 '16 at 20:30