ruby-on-rails – 如何根据父对象的状态验证嵌套模型对象?

我在轨道上写了一个向导形式例如一个模型对象的多个输入页面。

我的方法的基础是Ryan Bates的Multistep form Railscast:http://railscasts.com/episodes/217-multistep-forms中描述的(如果有人想知道下面的一些代码的原因)。

在这里审查的对象是“参与者”,其中有一个“地址”

我的问题是,我只想验证嵌套对象(地址),当用户尝试进行地址输入屏幕。这通过参与者模型“current_step”上的属性进行跟踪

所以我有一个参与者:

class Participant < ActiveRecord::Base
  has_one :address
  accepts_nested_attributes_for :address
  validates_presence_of :first_name, :last_name, :if => self.current_step == "name"
  ...
  def steps = %w[ name address confirm ] # the steps the wizard will follow
end

和地址:

class Address < ActiveRecord::Base
  belongs_to :participant
  validates_presence_of :address1, :state, :suburb, :postcode #, :if => participant.current_step == "address"
end

这种方法的原理是向导的每个步骤在控制器(未显示)上调用“创建”动作,并且仅在处理每个步骤时验证模型的子集。

目前,当我完成第一个屏幕(“名称”)并尝试进入地址步骤时,地址验证被触发,并且我被发送回到“名称”屏幕,其中有空白地址详细信息的验证错误。

所以我在这里尝试了一些方法,最后一部分是在上面显示的地址验证中注释掉的条件 – 我发现不起作用,因为我只建立参与者>地址对象,但不是拯救他们因此,@ participant.address获取地址对象,但是@ participant.address.participant为null,因为Address还没有一个nobody_id外键来查找它的父级。

我的努力的原因似乎是包含了超级方便的accept_nested_attributes_for方法。我期望使用validates_associated进行验证,但是我看到,accept_nested_attributes_for标签都很好地传播表单参数,以创建嵌套的模型对象,还可以确保参与者#有效?方法调用所有情况下的地址验证。

所以我的困境是如何最好地使用参与者#有效?基于参与者的current_step参数的部分完整模型的有效方法?

编辑 – 更新以删除额外的信息,并提炼到核心问题

最佳答案
在地址模型中添加虚拟属性:

class Address < ActiveRecord::Base
  belongs_to :participant
  attr_accessor :skip_validation
  validates_presence_of :address1, :state, :suburb, :postcode, 
                           :unless => :skip_validation 
end

设置current_step时,设置地址对象的虚拟属性。

class Participant < ActiveRecord::Base
  has_one :address
  accepts_nested_attributes_for :address
  attr_accessor :current_step
  validates_presence_of :first_name, :last_name, 
                         :if => lambda {|r| r.current_step == "name"}


  def current_step=(value)
    unless (value == "address")
      address.skip_validation = true
    end    
    @current_step = value 
  end    
end

转载注明原文:ruby-on-rails – 如何根据父对象的状态验证嵌套模型对象? - 代码日志