Rails 模型 default_value 方法与 presence true 冲突

Rails model default_value method conflict with presence true

我有这个简化模型:

class Contract < ActiveRecord::Base

  belongs_to :user   belongs_to :plan

  before_validation :set_default_is_voided   
  before_validation :set_default_expiration

  validates :user, presence: true
  validates :plan, presence: true
  validates :contract_date, presence: true
  validates :is_voided, presence: true
  validates :expiration, presence: true

  protected

  def set_default_is_voided
    if self.is_voided.nil?
      self.is_voided = false
      ap self.is_voided.present?
      ap self.is_voided
    end
  end

  def set_default_expiration
    if self.contract_date.present?
      self.expiration = self.contract_date+1.month
    end
  end

end

而这个 rspec 简化测试:

context "Should create default values" do
  it "Have to create is_voided" do
    user = FactoryGirl.create(:user)
    plan = FactoryGirl.create(:planContract)
    ap "HERE"
    contractDefault = FactoryGirl.create(:contractDefault, plan: plan, user: user)
    ap contractDefault
    expect(contractDefault.is_voided).to eq(false)
  end
  it "Have to create expiration" do
    #expect(contract.expiration).should eq(Date.today()+1.month)
  end
end

工厂女郎:

FactoryGirl.define do
  factory :contractVoid, class:Contract do
  end
  factory :contractDefault, class:Contract do
    contract_date Date.today
  end
end

此测试失败并显示“is_voided 不能为空”。

问题是: 为什么 before_validation 中的方法 "set_default_is_voided" 没有通过 presence true 验证?而且,self.is_voided.present? return false,为什么开心?

你自己回答了为什么 set_default_is_voided 没有通过 presence: true 验证,即 self.is_voided.present? returns false,这presence: true是这样决定的。

self.is_voided.present? returns false 因为 false.present? == falseA concise explanation of nil v. empty v. blank in Ruby on Rails

请参阅 Rails: how do I validate that something is a boolean? 以了解一种验证布尔字段不是 nil 的方法。

有关 blank? 定义背后动机的问答,请参阅 http://www.quora.com/Why-does-Rails-make-false-blank-true