Reputation: 643
im trying to use ajax on acts_as_votable gem so the page doesnt refresh on a vote/upvote. I've adjused the controller methods for this, and added remote true on the links. However i think the only thing left are the two .js.erb files. ive looked around on here and the ruby documentation and i cant seem to find how to do it for this instance. thanks
VM23182:1 Uncaught ReferenceError: $ is not defined
at <anonymous>:1:1
at processResponse (application-50000f29e1bf2752ae7e56dda39f10dd0f67a47aea5c3f07ed0d933f3e1a256a.js:268)
at application-50000f29e1bf2752ae7e56dda39f10dd0f67a47aea5c3f07ed0d933f3e1a256a.js:196
at XMLHttpRequest.xhr.onreadystatechange (application-50000f29e1bf2752ae7e56dda39f10dd0f67a47aea5c3f07ed0d933f3e1a256a.js:251)
`$('.unlike_post').bind('ajax:success', function(){
$(this).parent().parent().find('.vote_count').html('<%= escape_javascript @post.votes_for.size.to_s %>');
$(this).closest('.unlike_post').hide();
$(this).closest('.votes').html(' <%= link_to "Like", like_post_path(@post), remote: true, method: :get, class: "like_post" %>');
});`
Started PUT "/tweets/60/like" for 127.0.0.1 at 2018-10-02 00:06:40 +0100
Processing by TweetsController#upvote as JS
Parameters: {"id"=>"60"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 3], ["LIMIT", 1]]
↳ /Users/benherring/.rbenv/versions/2.4.4/lib/ruby/gems/2.4.0/gems/activerecord-5.2.1/lib/active_record/log_subscriber.rb:98
Tweet Load (0.2ms) SELECT "tweets".* FROM "tweets" WHERE "tweets"."id" = $1 LIMIT $2 [["id", 60], ["LIMIT", 1]]
↳ app/controllers/tweets_controller.rb:57
(0.4ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."voter_id" = $3 AND "votes"."vote_scope" IS NULL AND "votes"."voter_type" = $4 [["votable_id", 60], ["votable_type", "Tweet"], ["voter_id", 3], ["voter_type", "User"]]
↳ app/controllers/tweets_controller.rb:58
ActsAsVotable::Vote Load (0.6ms) SELECT "votes".* FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."voter_id" = $3 AND "votes"."vote_scope" IS NULL AND "votes"."voter_type" = $4 ORDER BY "votes"."id" DESC LIMIT $5 [["votable_id", 60], ["votable_type", "Tweet"], ["voter_id", 3], ["voter_type", "User"], ["LIMIT", 1]]
↳ app/controllers/tweets_controller.rb:58
(0.2ms) BEGIN
↳ app/controllers/tweets_controller.rb:58
ActsAsVotable::Vote Update (0.5ms) UPDATE "votes" SET "updated_at" = $1, "vote_flag" = $2 WHERE "votes"."id" = $3 [["updated_at", "2018-10-01 23:06:40.357671"], ["vote_flag", true], ["id", 10]]
↳ app/controllers/tweets_controller.rb:58
(1.3ms) COMMIT
↳ app/controllers/tweets_controller.rb:58
Rendering tweets/vote.js.erb
(0.4ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."vote_flag" = $3 [["votable_id", 60], ["votable_type", "Tweet"], ["vote_flag", true]]
↳ app/views/tweets/_icons.html.erb:5
(0.6ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."votable_id" = $1 AND "votes"."votable_type" = $2 AND "votes"."vote_flag" = $3 [["votable_id", 60], ["votable_type", "Tweet"], ["vote_flag", false]]
↳ app/views/tweets/_icons.html.erb:9
Rendered tweets/_icons.html.erb (5.7ms)
Rendered tweets/vote.js.erb (8.7ms)
Completed 200 OK in 40ms (Views: 21.0ms | ActiveRecord: 4.7ms)
resources :tweets do
member do
put "like", to: "tweets#upvote"
put "dislike", to: "tweets#downvote"
end
<div id="tweets">
<% @tweets.each do |tweet| %>
<div class="card">
<h4 class = "username"><%= link_to tweet.user.username, user_path(tweet.user) %></h4>
<p class="tweet-content"><%= tweet.content %></p>
<p class="date"><%= tweet.created_at.strftime("%B %d %Y, %l:%M%P") %></p>
<div class="icons">
<%= link_to like_tweet_path(tweet),remote: true , method: :put do %>
<div class="upvote"><i class="fas fa-thumbs-up"></i> <%= tweet.get_upvotes.size %></div>
<% end %>
<%= link_to dislike_tweet_path(tweet), remote: true, method: :put do %>
<div><i class="fas fa-thumbs-down"></i> <%= tweet.get_downvotes.size %></div>
<% end %>
</div>
</div>
<% end %>
</div>
def upvote
@tweet = Tweet.find(params[:id])
@tweet.upvote_by current_user
respond_to do |format|
format.html {redirect_to :tweets}
format.js {render layout: false}
# redirect_to :tweets
# redirect_to :tweets
# if request.xhr?
# head :ok
# else
end
end
def downvote
@tweet = Tweet.find(params[:id])
@tweet.downvote_by current_user
respond_to do |format|
format.html {redirect_to :tweets}
format.js {render layout: false}
# redirect_to :tweets
end
end
Upvotes: 0
Views: 42
Reputation: 905
It looks like the way you initially started on is to attach handlers to the buttons that listen for successful requests. This is a fair way to do it, but - since you're already using Rails UJS - there's a possibly "better" way.
With Rails UJS, JS files returned from a remote action are automatically executed. In my opinion, a more idiomatic Rails way to do this is as follows:
Extract out the icons into their own template:
<div id="tweets">
<% @tweets.each do |tweet| %>
<div id="tweet-<%= tweet.id %>" class="card">
<h4 class = "username"><%= link_to tweet.user.username, user_path(tweet.user) %></h4>
<p class="tweet-content"><%= tweet.content %></p>
<p class="date"><%= tweet.created_at.strftime("%B %d %Y, %l:%M%P") %></p>
<%= render 'icons', tweet: tweet %>
</div>
<% end %>
</div>
tweets/_icons.html.erb
:
<div class="icons">
<%= link_to like_tweet_path(tweet),remote: true , method: :put do %>
<div class="upvote"><i class="fas fa-thumbs-up"></i> <%= tweet.get_upvotes.size %></div>
<% end %>
<%= link_to dislike_tweet_path(tweet), remote: true, method: :put do %>
<div class="downvote"><i class="fas fa-thumbs-down"></i> <%= tweet.get_downvotes.size %></div>
<% end %>
</div>
Then, in your upvote/downvote controller actions you would format.js { render 'vote' }
which would live at tweets/vote.js.erb
and look like:
document.querySelector('#tweet-<%= @tweet.id %> .icons').outerHTML = '<%= j render('icons', tweet: @tweet) %>';
At this point, you're now free to modify tweets/_icons.html.erb
to provide extra functionality (e.g. visual feedback on votes or changing the URL of the links to undo a vote).
Keeping this "older" jQuery method for those people who encounter a similar issue and are using jQuery. Though, really, you probably don't need it.
$('#tweet-<%= @tweet.id %> .icons').replaceWith('<%= j render('icons', tweet: @tweet) %>');
Upvotes: 1