7

我有一个表格供用户在他们的个人资料页面上创建一个问题(除了用户模型之外,还有一个问题模型,带有嵌套的答案)。它从用户个人资料页面 /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" 

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

更新用户控制器的 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>
4

2 回答 2

1

首先,使用 usingredirect_to而不是render不会重新填充表单的原因是,当 you 时redirect_to,操作的控制器逻辑运行,而 usingrender忽略了控制器逻辑。

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

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

当 you 时,它会使用您的操作中的代码与set一起redirect_to current_user呈现:show.html.erb@questionshow

@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

然后将您的表单指向该页面,例如:

<%= form_for(@question, url: users_path(@question.user) do |f| %>
  ...
<% end %>

(取决于您的路线是如何设置和命名的)。当然,到那时,整个事情变得可怕地缺乏 RESTful,有点混乱,而且绝对不是 Rails 的做事方式。(另一个更糟糕的选择是重定向回来并通过 get 查询传递参数。)在我看来,你会因为一点点收获而失去很多,我不确定我是否真的会推荐它。

于 2013-02-28T05:30:40.580 回答
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=>"users", :action=>"show"。就像是:

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

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

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

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
于 2013-02-28T05:31:40.113 回答