开发者

Rails 3 rendering form with an array of nested attributes after failing validation

I have question model which has many options.

In my question controller new action I create five options ready for my user

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

In the view I loop through all options

- 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")

My question model looks like this

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

And my question controller create action

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

Now, when I enter only two options in the form and hit the create button the validation prevents the model from being saved. Which is good. But when the create action renders the new action again, only the option fields that I filled are showing up. The three option fields which were left blank have disappeared.

If I replace the "@question.save" in my create action with "false", the behavior is the same. So this suggests that something in the way I create the @question variable in the create action is responsible for throwing away my empty options.

But if I instead remove the :reject_if from my question model the empty options are showing up after a failing question save as expected. (I have a presence validation for the option attribute in my option model) So this tells me that there is nothing wrong in the way I create the @question variable in the create action. It is not throwing away the empty options. So where they are kicked out?

There was one pretty similar question, but the answer in there is not something I would like to do. Though it might be something I have to do. rails 开发者_开发知识库fields_for does not render after validation error on nested form

EDIT

After some more study with rails console I noticed that it truly is the creation of @question variable where the empty options get thrown away. This happens because I have the reject_if defined in the question model. After commenting the reject_if out from the model the empty options were added into the @question variable.

So I guess I need to remove the reject_if and use after_save callback to destroy empty options from the database. This way I will have the empty options going along with the question until the question is saved.


I'm answering my own question because I got the issue solved.

Blank "options" were removed from the "question" because of reject_if in the "question" model. The reject_if statement was applied when the code below was executed, and therefore blank "options" were removed.

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

I replaced the reject_if with an after_save callback which removes the options which were left blank.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜