如何在重定向到另一个操作时传递模型,以便在重定向的视图中显示模型错误

时间:2016-04-14 19:34:01

标签: ruby-on-rails ruby ruby-on-rails-4

我想在@comment上显示新articles\view.html.erb的验证错误,因为它无法通过comments#create保留评论。

TLDR ,我使用带有rails 4.2.6和ruby 2.2.3的Getting Started教程创建了一个博客。

博客有很多文章,每篇文章都有很多评论

根据本教程,发布新评论的表单位于articles\view.html.erb,并且会保留在comments#create中。发布新评论后,它会再次重定向到articles#show

class Article < ActiveRecord::Base
  has_many :comments
  validates :title, presence: true, length: { minimum: 5 }
end

class Comment < ActiveRecord::Base
  belongs_to :article
end

我使用相同的观点 - articles/show.html.erb - 显示文章,其评论并发布新评论

<p><strong>Title:</strong><%= @article.title %></
<p><strong>Text:</strong><%= @article.text %></p>

<h2>Comments</h2>
<% @article.comments.each do |comment| %>
  <p><strong>Commenter:</strong><%= comment.commenter %></p>
  <p><strong>Comment:</strong><%= comment.body %></p>
<% end %>

<h2>Add a comment:</h2>
<%= form_for([@article, @article.comments.build]) do |f| %>
  <p><%= f.label :commenter %><br><%= f.text_field :commenter %></p>
  <p><%= f.label :body %><br><%= f.text_area :body %></p>
  <p><%= f.submit %></p>
<% end %>

<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>

通过articles_controller

def show
  @article = Article.find(params[:id])
end

comments_controller发布新评论

def create
  @article = Article.find(params[:article_id])
  @comment = @article.comments.create(comment_params)
  redirect_to article_path(@article)
end

按预期工作:)

这是我的问题开始的地方......

我决定进一步为评论模型

添加一些验证
class Comment < ActiveRecord::Base
  belongs_to :article   
  validates :commenter, presence: true
  validates :body, presence: true
end 

并在无法保存时显示注释错误。

首先,我尝试通过文章模型显示错误

<% if @article.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved:</h2>
    <ul><% @article.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %></ul>
  </div>
<% end %>

然后我尝试使用@comment

中的全局var articles_controller
def show
  @article = Article.find(params[:id])
  @comment = @article.comments.build
end

<% 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 |msg| %>
      <li><%= msg %></li>
    <% end %></ul>
  </div>
<% end %>

它也不起作用。

据我所知,由于我提交了新评论,因此无效,我重定向到文章show action redirect_to article_path(@article) - 如果成功或不保存新评论 - 因此创建了一个新的评论实例,用其错误覆盖了前一个评论实例。

我最好的解决方案是使用flash属性和错误消息。看起来像这样

comments_controller

def create
  @article = Article.find(params[:article_id])
  @comment = @article.comments.create(comments_params)
  redirect_to article_path(@article), flash: {new_article_errors: @comments.errors.full_messages}
end 

articles/show.html.erb

<% unless flash[:new_comment_errors].nil?  %>
  <div id="error_explanation">
    <h2>
      <%= pluralize(flash[:new_comment_errors].count, "error") %> prohibited this comment from begin saved:
    </h2>
    <ul>
      <% flash[:new_comment_errors].each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>

但这也不是最好的解决方案。它显示错误但丢失已填充的值(表单已清除)。

我是否需要通过redirect_to传递@comment?这样的事情

comments_controller

def create
  @article = Article.find(params[:article_id])
  @comment = @article.comments.build(comments_params)

  if @comment.save
    redirect_to article_path(@article)
  else 
    redirect_to article_path(:comment => params[:comment] )
  end
end

article_controller

def show
  @article = Article.find(params[:id])
  @comment = @article.comments.build

  @comment.valid? if params[:comment]
end

现在我收到了No route matches错误。我应该创建一个收到params[:comment]的新操作吗?或编辑节目路线以接收它?

我已经阅读了Nested model validation - errors don't show但没有帮助,因为他们建议在comments_controller中创建新操作而我不希望这样(新帖子需要在article/show.html.erb)。

Nested Model Form Part 1Nested Model Form Part 2也没有帮助。

感谢您的时间和帮助!

1 个答案:

答案 0 :(得分:1)

而不是重定向到ArticlesController#show方法(正如您所发现的那样会导致所有实例变量丢失),而是可以渲染显示视图。

if @comment.save
  redirect_to article_path(@article)
else 
  render :template => 'articles/show'
end

您已经拥有@template@comment个实例变量,因此它们将在渲染中使用。