无法在父资源显示页面上呈现嵌套资源的错误

时间:2018-09-06 16:45:35

标签: ruby-on-rails ruby actionview nested-resources

我有一个带有帖子和评论的基本“博客”应用程序。我想允许用户对post#show中的帖子发表评论,但我不确定如何在帖子中显示评论验证错误。

下面的代码将注释嵌套在帖子下,并将成功创建注释。当验证失败(例如空白评论)时,访问者将被重定向到展后页面,但评论错误消息丢失了。

现在CommentsController#create正在将用户重定向到他正在查看的post。另外,我尝试使用render 'posts/show'而不是重定向,但是最终以posts/1/comments而不是posts/1呈现页面。

对于在帖子/显示模板上显示的评论验证出错的任何帮助,将不胜感激。

路线

# config/routes.rb
Rails.application.routes.draw do
  resources :posts do
    resources :comments, only: [:create]
  end
end

模型

class Comment < ApplicationRecord
  belongs_to :post  
  validates :content, presence: true, length: { in: 6..20 }
end

class Post < ApplicationRecord
  has_many :comments
end

控制器

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def show
    @post = Post.find(params[:id])
  end
end


# app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.build(comment_params)

    if @comment.save
      # SAVE works fine
      redirect_to @post, notice: 'Comment was successfully created.'
    else
      # ERROR displays nothing on the post show page
      redirect_to @post
    end
  end

  private

  def comment_params
    params.require(:comment).permit(:content, :post_id)
  end
end

观看次数

# app/views/posts/show.html.erb
<p id="notice"><%= notice %></p>

<p>
  <strong>Title:</strong>
  <%= @post.title %>
</p>

<h2>Comments</h2>

<table>
  <thead>
    <tr>
      <th>Content</th>
    </tr>
  </thead>

  <tbody>
    <% @post.comments.each do |comment| %>
      <tr>
        <td><%= comment.content %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<h3>New Comment</h3>

<%= render 'comments/form', post: @post, comment: @post.comments.build %>
# app/views/comments/_form.html.erb
<%= form_with(model: [post, comment], local: true) do |form| %>
  <% if comment.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:</h2>

      <ul>
      <% comment.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :content %>
    <%= form.text_field :content %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

注意:我尝试避免使用accepts_nested_attributes_for,因为对于更复杂的用例,我感到非常混乱。

1 个答案:

答案 0 :(得分:2)

您不会看到错误消息,因为在失败的保存尝试中,您将重定向到其他控制器/操作;未保存的@comment对象不仅不可用,而且在呈现注释形式时在视图层中也被覆盖。尝试渲染posts/show操作中的CommentsController#create视图。

if @comment.save
  # SAVE works fine
  redirect_to @post, notice: 'Comment was successfully created.'
else
  render 'posts/show'
end

要执行此操作,您还需要将新评论的实例化从视图移动到PostsController#show操作。

# app/controllers/comments_controller.rb
class PostsController < ApplicationController
  def show
    @post = Post.find(params[:id])
    @comments = @post.comments
    @comment = Comment.new(post: @post)
  end
end

在加载到控制器中的@comments上进行迭代。新的评价不应包括在其中。呈现表单时,请使用@comment变量。保存之前,请记住将新评论与帖子关联。

<h2>Comments</h2>

<table>
  <thead>
    <tr>
      <th>Content</th>
    </tr>
  </thead>

  <tbody>
    <% @comments.each do |comment| %>
      <tr>
        <td><%= comment.content %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>
<h3>New Comment</h3>

<%= render 'comments/form', post: @post, comment: @comment %>

通过这种方式,posts/show视图应同时适用于两个控制器动作;尝试保存后,应保留@comment对象的状态及其错误。