如何验证嵌套对象中的单个属性

时间:2012-04-03 21:37:59

标签: ruby-on-rails validation activerecord

我是Rails和Ruby的新手。在我看来,我有2个单选按钮,询问这个人是否是美国居民。如果是,则显示状态选择。如果不是,则显示国家选择。

如果该人是美国居民,我试图验证是否已选定州。

如何创建验证并从addresses_attributes中访问状态?

这是我的模特:

class Person < ActiveRecord::Base
  has_many :addresses, :as => :addressable
  has_one :user

  accepts_nested_attributes_for :user, :allow_destroy => true
  accepts_nested_attributes_for :addresses

  attr_accessor   :resident
  attr_accessible :campaign_id,
                  :first_name,
                  :last_name,
                  :user_attributes,
                  :addresses_attributes,
                  :resident

  validates :first_name, :presence => true
  validates :last_name, :presence => true

  validates_presence_of :resident, :message => "must be selected"

end

这些是发送的相关参数:

"resident"=>"true",
 "addresses_attributes"=>{"0"=>{"country_code"=>"",
 "state"=>""}}

3 个答案:

答案 0 :(得分:1)

您需要自定义验证方法。

   validate :check_state_presence 

    def check_state_presence 
     if self.resident && !self.addresses.state.present?
        self.errors[:base] << "You need to Select State if you are a US resident."
     end 
    end 

答案 1 :(得分:1)

您可以使用validates_inclusion_of对其进行排序。

Ruby API说:

  

如果要验证是否存在布尔字段(实际值为true且&gt;为false),则需要使用validates_inclusion_of:field_name,:in =&gt; [true,false]。

     

这是由于Object#blank的方式?处理布尔值:false.blank? #=&gt;真。

答案 2 :(得分:0)

+1给@VelLes帮助我指向正确的方向。我正在回答我自己的问题,因为我必须更改@VelLes示例以使其工作,我希望其他人看到完整的解决方案。

由于我使用attr_accessor作为虚拟属性,当真/假值来自单选按钮时,它将被存储为字符串。因此,如果self.resident =“false”,它将被评估为true。

您可以执行self.resident == 'false'或转换为布尔值并添加新的self.resident?方法。我选择了后者。

布尔转换来自this blog post,添加到config / initializers

中的文件
class String
  def to_bool
    return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
    return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
    raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
  end
end

我的最终代码是:

validate :check_state_presence 

def resident?
  resident.to_bool
end

def check_state_presence 
 if self.resident? && !self.addresses[0].state.present?
   #the inline version of the error message 
   self.addresses[0].errors.add(:state, "must be selected")
 end 
end 

如果有更好的'轨道'方式,请告诉我!