2

Okay, I'm starting to pull my hair out on this one. I'm new to rails, and was following a tutorial on making a pinterest style app. I finished it but wasn't happy with the up-voting system.

It was refreshing the page every time I clicked to up vote. So I found some post about it and did exactly what it said. It kept loading a page that showed me the js code instead of executing it.

This morning I changed a "put" to "get" then back again, and now it's working... NO IDEA what happened to change it.

BUT, now it's up voting every post on the page instead of just the one I click on. When I hover over the links, they all point to the proper ID for that link.

Here's the code from the controller:

def upvote
@pin.upvote_by current_user
respond_to do |format|
  format.html { redirect_to :back }
  format.js { render :layout => false }
  format.json 
end
end

And the view (haml):

.btn-group.pull-right
      = link_to like_pin_path(pin), method: :put, remote: true, class: "btn btn-like" do
        %span.glyphicon.glyphicon-heart
          = pin.get_upvotes.size

Upvote.js.erb:

$('.glyphicon-heart').html('<%=@pin.get_upvotes.size%>');

Routes.rb

Rails.application.routes.draw do
  devise_for :users
  resources :pins do
    member do
      put "like", to: "pins#upvote", defaults: { format: 'js' }
    end
  end

  root "pins#index"
end

Here's the log from the console when a like button is clicked:

Started PUT "/pins/10/like" for ::1 at 2015-12-08 11:40:02 -0600
Processing by PinsController#upvote as JS
Parameters: {"id"=>"10"}
Pin Load (0.2ms)  SELECT  "pins".* FROM "pins" WHERE "pins"."id" = ? LIMIT 1  [["id", 10]]
User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["id", 2]]
(0.3ms)  SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."voter_id" = ? AND "votes"."voter_type" = ? AND "votes"."vote_scope" IS NULL  [["votable_id", 10], ["votable_type", "Pin"], ["voter_id", 2], ["voter_type", "User"]]
ActsAsVotable::Vote Load (0.6ms)  SELECT  "votes".* FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."voter_id" = ? AND "votes"."voter_type" = ? AND "votes"."vote_scope" IS NULL  ORDER BY "votes"."id" DESC LIMIT 1  [["votable_id", 10], ["votable_type", "Pin"], ["voter_id", 2], ["voter_type", "User"]]
(0.2ms)  begin transaction
(0.1ms)  commit transaction
(0.2ms)  SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = ? AND "votes"."votable_type" = ? AND "votes"."vote_flag" = ? AND "votes"."vote_scope" IS NULL  [["votable_id", 10], ["votable_type", "Pin"], ["vote_flag", "t"]]
Rendered pins/upvote.js.erb (4.4ms)
Completed 200 OK in 25ms (Views: 9.4ms | ActiveRecord: 1.8ms)

I'm sure it's something really simple but ajax/js are even newer to me than rails.

Let me know if there's anything else I need to post. Any help will be so greatly appreciated!

Also for future reference, what would make the link load a page with the js code instead of executing the code? Since I don't feel like I changed anything that drastic today, I don't know how I got past that. I'm glad I did, but it would be helpful to know HOW.

tdog
  • 147
  • 2
  • 10

1 Answers1

1

It's doing that because your JS is technically targeting all the links with that class. Instead you could append the model's id of the individual pin to the link's class or create a data attribute but it's entirely up to you. In doing so it'll only target the one link that's clicked.

UPDATE:

Essentially you'll want to assign a class (instance's id) to a container div holding the vote button: pin-#{pin.id} for index view and pin-#{@pin.id} for show view.

Controller

def upvote
  @pin.upvote_by current_user

  respond_to do |format|
    format.js { render "upvote.js.erb" }
  end
end

Routes

...
resources :pins do
  member do
    put :upvote
  end
end

Index View

...
%div{class: "btn-group pull-right pin-#{pin.id}"}
  = render "upvote", pin: pin

Show View

...
.col-md-6
    %div{class: "btn-group pull-right pin-#{@pin.id}"}
      = render "upvote", pin: @pin
      -if user_signed_in?
      = 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"

_upvote.html.haml

= link_to upvote_pin_path(pin), method: :put, remote: :true, class: "btn btn-default btn-like" do
  %span.glyphicon.glyphicon-heart
  = pin.get_upvotes.size

upvote.js.erb

$(".pin-<%= @pin.id %>").html("<%= escape_javascript(render 'upvote', pin: @pin) %>");
Carl Edwards
  • 13,826
  • 11
  • 57
  • 119
  • Unfortunately, now it's updating the votes but not showing up automatically anymore, only when I refresh. It also seems to have broken the functionality on the show view which was working before. – tdog Dec 09 '15 at 05:32
  • Updated my answer. Give it a look and let me know how things work out. – Carl Edwards Dec 09 '15 at 19:23
  • Hmm I'm afraid that didn't work either. Though it still updates the upvote count when I refresh. I don't have a pins partial, could that be the issue? – tdog Dec 10 '15 at 20:39
  • Possibly. Let's try this. Put that portion of code to upvote pins in its own partial `_upvote.html.slim` (assuming you're using Slim as your pre-compiler). Then render that partial in your main view template. Let me know what happens. I'll also update my answer to give you a better idea. – Carl Edwards Dec 10 '15 at 21:01
  • Same result, it's updating the votes but not showing that until the page reloads. I really appreciate you taking the time to help me. Hopefully we can get to the bottom of this! It is working in updating the votes at least, and has worked before with instantly showing the votes so I know it is possible haha. Can't give up! – tdog Dec 11 '15 at 15:12
  • Are you free to chat? – Carl Edwards Dec 11 '15 at 15:12
  • Also when you click the link to upvote are you getting any error messages in your rails console? If so what is it saying? – Carl Edwards Dec 11 '15 at 15:18
  • I changed it back to how it was before this last change, and am not getting any errors in the rails console. Where can we chat? Thanks Carl – tdog Dec 11 '15 at 23:07
  • Usually after number of comments there should be a link to continue the discussion in a chat. Don't know the exact amount that triggers this but so far nothing has come up for me. I should be around tomorrow so hopefully we can link up then. – Carl Edwards Dec 12 '15 at 04:04
  • Can you also post how you're routes are setup? – Carl Edwards Dec 12 '15 at 04:06
  • I added the routes.rb code to the original post. Thanks – tdog Dec 13 '15 at 15:35
  • Thanks. So from what I see, you need to change `like` to `:upvote` in your routes file. The upvote action you have setup in your controller is never being called because of this naming mixup. Check out the update I've done to your routes partial's `link_to` and see if that works. – Carl Edwards Dec 14 '15 at 00:15
  • P.S. I also made a minor adjustment to the class name for the link to upvote pins in the partial and js.erb file. This way the class name would read as `.pin-1` vs. just a numeric value. – Carl Edwards Dec 14 '15 at 00:21
  • I don't know what I'm doing wrong in the view template, but it's giving me an error for illegal nesting. I replaced the link_to line with your code. Not quite sure how to set that up I guess. The like to :upvote thing is funny because I was following a tutorial. I really appreciate your patience with this. – tdog Dec 15 '15 at 17:27
  • No problem at all. That error means that something's off in the way you have your Haml written. I'm not too versed in it's markup but let's try this. I think the only thing I changed was adding an additional string argument, "Upvote". Remove that and see if the error goes away. – Carl Edwards Dec 15 '15 at 17:32
  • Sorry, where am I removing that from? The partial? – tdog Dec 15 '15 at 20:25
  • Like this: `= link_to upvote_pin_path(pin), method: :put, remote: true, class: "btn btn-like pin-<%= pin.id %>"`. – Carl Edwards Dec 15 '15 at 20:39
  • Okay I tried that, and it's still working behind the scenes but not refreshing the vote count. I've been trying to find other working examples of this, but I've had no luck, it all just seems like how I had it before when it liked everything on the page. – tdog Dec 15 '15 at 20:55
  • What directory is your `upvote.js.erb` file in? `app/views/pins`? – Carl Edwards Dec 15 '15 at 21:01
  • Also, what happens if you remove `format.html { redirect_to :back }` and `format.json` in your pins controller's `upvote` action? – Carl Edwards Dec 15 '15 at 21:03
  • Also, I still don't have the `<%= render "upvote", pin: @pin %>` part in the index view because of the haml error. I tried to format that several different ways and got various different errors so I just left it as it was before. – tdog Dec 15 '15 at 21:04
  • Yes, that's where the `upvote.js.erb` file is, and with that code removed it is still the same result. – tdog Dec 15 '15 at 21:08
  • In response to your previous post, can you remove everything in that partial **except** for the `link_to`: `= link_to upvote_pin_path(pin), method: :put, remote: true, class: "btn btn-like pin-<%= pin.id %>"`? We can work backwards if that does the trick. – Carl Edwards Dec 15 '15 at 21:08
  • I'm afraid you lost me on that one, that's already how the partial is set up. – tdog Dec 15 '15 at 21:11
  • I meant just having that line only in your file vs the code you posted in your question. Would you be able to throw this project up on Github for me to take a look at? – Carl Edwards Dec 15 '15 at 21:13
  • Thanks, I'll take a look and see what's up. – Carl Edwards Dec 15 '15 at 21:25
  • Whoops, I had forgotten to add the changes we just made, did that just now. – tdog Dec 15 '15 at 21:33
  • Made an update to my answer. I had accidentally assigned an idea to the anchor tag instead of the container div and also had things incorrectly interpolated. Tested it out on my machine and things now seem to be working. Let me know you have any questions regarding the changes. – Carl Edwards Dec 16 '15 at 14:06
  • CARL, you are the man! I'm not completely sure what kind of magic you've done, but I love it and appreciate the help so much. Time to dive head first into some other scary concept! (how hard would it be to add the down vote option to the same link?) PS I tried to upvote your post but I'm too new on here. Thanks again. – tdog Dec 17 '15 at 15:30