当Rails只应更新现有页面中的局部视图时,它会呈现局部视图

时间:2014-06-30 21:28:20

标签: javascript ajax ruby-on-rails-4 partials

我尝试通过AJAX对帖子进行上/下投票,以便用户不必刷新页面以查看更新的分数。但是,单击投票链接时,用户将重定向到仅显示部分视图的页面。甚至不显示父视图。如何在不刷新整个页面的情况下更新索引页面中的partial?我怀疑问题在于我的投票'控制器动作。到目前为止,这是我的代码:

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

1 个答案:

答案 0 :(得分:1)

您的回复的js分支错过了指示应呈现哪个视图的块:

respond_to do |format|
  format.html { render partial: 'score', locals: {post: @post} }
  format.js { render partial: 'score', locals: {post: @post} }
end

否则rails默认为渲染vote.js,因为这是您的控制器方法名称。也许这只是一个错字,但你的文件应该被命名为_score.js.erb(部分),就像HTML版本一样。

<强>更新

再次审核了您的代码,可能只需将score.js.erb重命名为vote.js.erb,因为您在那里呈现_score部分。

从设计的角度来看,最干净,最干燥的解决方案是跳过format调用的块,并拥有如下文件:

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