在验证失败时重新填充表单

时间:2013-02-28 02:30:18

标签: ruby-on-rails

我有一个表单供用户在他们的个人资料页面上创建一个问题(除了用户模型,还有一个问题模型,有嵌套的答案)。它从用户个人资料页面/views/users/show.html.erb提交到questions_controller.rb的创建操作。如果它没有验证,我认为Rails的默认值是呈现表单(表单中的无效信息供用户编辑)。但是,由于我是从用户个人资料页面提交问题模型的表单,因此在验证失败时不会发生预填充;用户被迫再次输入表单中的所有信息。在这种情况下,是否有办法在用户显示页面上获取表单以填写提交前输入的信息?

questions_controller

def create
    @question = current_user.questions.build(params[:kestion])

    if @question.save
      redirect_to current_user, :notice => "Successfully created question."
    else
      ###render  :action => 'show'
      redirect_to current_user

    end
  end

更新 我也改变了创建方法的结束

Redirect ( : back ), :notice => "something went wrong.try again" 

但是我仍然无法填写表单,并且验证错误消息也没有显示,只显示闪存通知。

更新 用户控制器的show方法创建新问题(与用户一起)

   def show
        @user = User.find(params[:id])
        @question = Question.new 
        3.times {@question.answers.build}

   end 

/views/users/show.html.erb

<%= form_for @question do |f| %>
   <% if @question.errors.any? %>
  <h2><%= pluralize(@question.errors.count, "error") %> prohibited this question
    from being saved: </h2>
    <ul>
      <% @question.errors.full_messages.each do |msg| %>
      <li> <%= msg %></li>
    <% end %>
    </ul>   
  <% end %>
  <p>
     <%= f.label :content, "Question"%>
    <%= f.text_area :content, :class => 'span4', :rows => 1 %>   
  </p>
  <p>
    <%= f.label :link, "QuoraLink" %>
    <%= f.text_field :link, :class => 'span4', :rows => 1  %>   
  </p>  
  <%= f.fields_for :answers do |builder| %>
    <p>
      <%= render 'answer_fields', :f => builder %>
    </p>
   <% end %>
   <p><%= link_to_add_fields "Add Answer", f, :answers %></p>
  <p><%= f.submit %></p>
<% end %>

answer_fields部分从问题部分呈现

<p class="fields">
<%= f.label :content, "Answer..." %>

  <%= f.text_field :content, :class => 'span3', :rows => 1%>

   <%= f.label :correctanswer, "Correct" %>
  <%= f.check_box :correctanswer, :class => 'span1' %>

   <%= link_to_remove_fields "remove answer", f %>      
</p>

2 个答案:

答案 0 :(得分:1)

首先,使用redirect_to代替render而不重新填充表单的原因是当您redirect_to时,操作的控制器逻辑会运行,而使用{{ 1}}忽略了控制器逻辑。

因此,当您render(“默认”行为)时,它会呈现render :action => 'show'show.html.erb设置如下:

@question

当您@question = current_user.questions.build(params[:kestion]) 时,它会使用redirect_to current_user操作中的代码设置show.html.erb来呈现@question

show

这就是为什么你得到一个新的(空白)表单,而不是预先填充的表单。

使用@question = Question.new 3.times {@question.answers.build} 真的是否重要?如果是,您需要使用redirect_to方法进行验证。例如,您可以将show方法重写为:

show

然后在该页面上制作表格点,例如:

def show
  @user = User.find(params[:id])
  if params.has_key?(:kestion)
    @question = @user.questions.build(params[:kestion])
  else
    @question = Question.new 
    3.times {@question.answers.build}
  end
end

(取决于您的路线设置和命名方式)。当然,到目前为止,整个事情变得非常糟糕,有点混乱,而且绝对不是Rails的做事方式。 (另一个更糟糕的选择是重定向并通过获取查询传递参数。)在我看来,你因为一个小的收益而损失很多,而且我不确定我是否真的推荐它。

答案 1 :(得分:1)

目前,在views / users / show.rb中,您可以

@question = Question.new

创建一个空的新问题。然后使用此空模型填充表单。 你可以做的是:

if session[:question]
  @question = @user.questions.new(session[:question])
  session[:question] = nil
  @question.valid? # run validations to to populate the errors[]
else
  @question = Question.new
end

现在剩下要做的就是在你的questions_controller中填充session [:question],然后重定向到:controller =&gt;“users”,:action =&gt;“show”。类似的东西:

if @question.save
  redirect_to current_user, :notice => "Successfully created question."
else
  session[:question] = params[:question]
  redirect_to current_user
end

您可能需要另外进行序列化/反序列化以填充/使用会话[:question]。我没有尝试编译,所以我不确定。

所有这些都是必需的,因为当您重定向到用户请求的处理结束时,用户浏览器会从您的服务器获取重定向状态代码并转到另一个页面,向您发送新请求(该请求落在路径上,以及最终控制器/动作,你重定向到)。因此,一旦从请求处理返回,所有变量都将丢失。对于下一个请求,您可以从头开始。

render :action => "show"方法(在原始脚手架中并且您注释掉了)工作,因为您没有返回给用户,而只是使用您已有的变量使用特定名称呈现模板(包括@question,调用'save'并失败,因此调用内部验证并填充错误对象。)

实际上,这提醒我你可能想要使用另一种方法。您可能希望填充所有必需的变量,而只是从该控制器渲染视图,而不是通过session []传递参数并重定向到UsersController。如下所示:

if @question.save
  redirect_to current_user, :notice => "Successfully created question."
else
  @user = current_user
  render "users/show"
end