I'm trying to implement up/down-voting a post through AJAX, so that users don't have to refresh the page to see the updated score. However, when the voting links are clicked, the user is redirected to a page that only displays the partial view. The parent view is not even displayed. How can I update the partial in the index page without refreshing the entire page? I suspect that the problem lies in my 'vote' controller action. Here is my code so far:
def vote
value = params[:type] == "up" ? 1 : -1
@post = Post.find(params[:id])
@post.add_or_update_evaluation(:votes, value, current_user)
respond_to do |format|
#I'm guessing the problem lies here.
format.html { render partial: 'score', locals: {post: @post} }
format.js
end
end
<td id="score_<%= post.id %>"><%= post.reputation_for(:votes).to_i %></td>
<% if user_signed_in? %>
<td>
<%= button_to "Upvote", vote_post_path(post, type: "up"), method: "post", class: "btn btn-success", remote: true %>
</td>
<td>
<%= button_to "Downvote", vote_post_path(post, type: "down"), method: "post", class: "btn btn-danger", remote: true %>
</td>
<% end %>
$('#score_<%= post.id %>').html("<%= escape_javaScript render partial: 'score', locals: {post: @post} %>");
<% @posts.each do |post| %>
<%= render partial: 'score', locals: {post: post} %>
...
<% end %>
//= require jquery
//= require jquery_ujs
//= require bootstrap.min
//= require turbolinks
//= require_tree .
The js
branch of your response misses the block that states which view should be rendered:
respond_to do |format|
format.html { render partial: 'score', locals: {post: @post} }
format.js { render partial: 'score', locals: {post: @post} }
end
Otherwise the rails default would be to render vote.js
, since this is your controller method name. And maybe it's just a typo but your file should be named _score.js.erb
(partial), just like the HTML version.
UPDATE
Having reviewed your code once more, maybe it's enough to simply rename score.js.erb
to vote.js.erb
, since you render the _score
partial in there.
And from a design point of view, the cleanest and driest solution would be to skip the blocks for the format
calls and have the files like so:
# posts_controllers.rb
def vote
value = params[:type] == "up" ? 1 : -1
@post = Post.find(params[:id])
@post.add_or_update_evaluation(:votes, value, current_user)
respond_to do |format|
format.html # this renders vote.html.erb
format.js # this renders vote.js.erb
end
end
# vote.html.erb
<%= render 'score', locals: { post: @post } %>
# vote.js.erb
$('#score_<%= @post.id %>').html("<%= escape_javaScript render partial: 'score', locals: { post: @post } %>");
# _score.html.haml
<td id="score_<%= post.id %>"><%= post.reputation_for(:votes).to_i %></td>
<% if user_signed_in? %>
<td>
<%= button_to "Upvote", vote_post_path(post, type: "up"), method: "post", class: "btn btn-success", remote: true %>
</td>
<td>
<%= button_to "Downvote", vote_post_path(post, type: "down"), method: "post", class: "btn btn-danger", remote: true %>
</td>
# index.html.erb
<%= render 'score', collection: @posts, as: :post %>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.