Rails 3在验证失败后使用嵌套属性数组呈现表单

时间:2011-07-11 21:37:34

标签: ruby-on-rails-3 nested-forms

我有问题模型,有很多选择。

在我的问题控制器新操作中,我为我的用户创建了五个选项

def new
  @question = Question.new

  5.times.with_index do |index|
    @question.options.build(:order => index)
  end

  respond_to do |format|
    format.html # new.html.erb
    format.xml  { render :xml => @question }
  end
end

在视图中,我遍历所有选项

- form_for(@question) do |f|
  .field                   
    = f.label :title, t("question.title")
    = show_errors_for(@question, :title)
    = f.text_field :title
  - @question.options.each do |option|
    - f.fields_for :options, option do |o|                                         
      .field                                                                       
        = o.label :option, t("question.option_no", { :index => option.order })     
        = o.text_field :option                                                     
        = o.hidden_field :order, :value => option.order                            
  .actions                                                                         
    = f.submit t("add_question.create")

我的问题模型看起来像这样

class Question < ActiveRecord::Base
  attr_accessible :title, :options_attributes

  belongs_to :user
  has_many :options

  accepts_nested_attributes_for :options, :reject_if => proc { |attributes| attributes['option'].blank? }

  validates :title, :length => { :maximum => 100 }, :presence => true
  validate :min_no_of_options

  def min_no_of_options
    if self.options.size < 3
      errors.add_to_base "Must have at least three options"
    end
  end
end

我的问题控制器创建动作

def create
  if current_user
    @question = current_user.questions.build(params[:question])
  else
    @question = Question.new(params[:question])
  end

  if @question.save
    redirect_to(@question, :success => t('question.flash_success'))
  else
    flash.now[:error] = t("question.flash_error")
    render :action => "new"
  end
end

现在,当我在表单中只输入两个选项并点击“创建”按钮时,验证会阻止保存模型。这很好。但是当create动作再次呈现新动作时,只会显示我填充的选项字段。留空的三个选项字段已消失。

如果我用“false”替换我的创建操作中的“@ question.save”,则行为是相同的。所以这表明我在create action中创建@question变量的方式有责任抛弃我的空选项。

但是如果我从我的问题模型中删除:reject_if,则在失败的问题保存之后会出现空选项。 (我在选项模型中对选项属性进行了状态验证)所以这告诉我在创建操作中创建@question变量的方式没有任何问题。它并没有丢掉空的选项。那么他们被踢出去了?

有一个非常相似的问题,但那里的答案并不是我想做的事情。虽然这可能是我必须要做的事情。 rails fields_for does not render after validation error on nested form

修改

在使用rails控制台进行更多研究之后,我注意到它确实是@question变量的创建,其中空选项被抛弃。发生这种情况是因为我在问题模型中定义了reject_if。在从模型中注释掉reject_if之后,空选项被添加到@question变量中。

所以我想我需要删除reject_if并使用after_save回调来从数据库中销毁空选项。通过这种方式,我将在问题保存之前将空选项与问题一起使用。

1 个答案:

答案 0 :(得分:3)

我正在回答我自己的问题,因为我解决了问题。

由于“问题”模型中的reject_if,空白“选项”已从“问题”中删除。执行下面的代码时会应用reject_if语句,因此删除了空白的“选项”。

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

我用after_save回调替换了reject_if,删除了留空的选项。