简体   繁体   中英

Rails is rendering partial view, when it should only be updating the partial view in an existing page

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:

/app/controllers/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|
    #I'm guessing the problem lies here.
    format.html { render partial: 'score', locals: {post: @post} }
    format.js
  end
end

/app/views/posts/_score.html.erb

<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 %>

/app/views/posts/score.js.erb

$('#score_<%= post.id %>').html("<%= escape_javaScript render partial: 'score', locals: {post: @post} %>");

/app/views/posts/index.html.erb

<% @posts.each do |post| %>
  <%= render partial: 'score', locals: {post: post} %>
  ...
<% end %>

/app/assets/javascripts/application.js

//= 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM