2

我对模型的属性进行了以下验证:

validates :on_ride_photo,
  presence: true,
  inclusion: { in: [true, false] }

然后我有以下测试:

context 'on_ride_photo' do
  it { should validate_presence_of(:on_ride_photo) }
  it { should allow_value(true).for(:on_ride_photo) }
  it { should allow_value(false).for(:on_ride_photo) }
  it { should_not allow_value(nil).for(:on_ride_photo) }
  it { should_not allow_value(4).for(:on_ride_photo) }
  it { should_not allow_value('yes').for(:on_ride_photo) }
end

但是在运行我的规范时出现以下错误:

2) Coaster validations should allow on_ride_photo to be set to false
   Failure/Error: it { should allow_value(false).for(:on_ride_photo) }
     Did not expect errors  when on_ride_photo is set to false, got error:
   # ./spec/models/coaster_spec.rb:86:in `block (3 levels) in <top (required)>'

我想允许 false 作为有效值的事实是否被它必须存在并且 false 被归类为不存在的事实所推翻?如果是这样,那么我该如何解决这个问题?

4

2 回答 2

2

是的,问题在于presence: true,它检查属性是否不是Object#blank?。由于验证是附加的,因此该inclusion:子句不能“覆盖”false未通过presence测试的事实。

以下来自http://edgeguides.rubyonrails.org/active_record_validations.html#presence

因为false.blank?is true,如果你想验证一个布尔字段的存在,你应该使用validates :field_name, inclusion: { in: [true, false] }.

有关如何处理布尔字段的讨论,请参阅Billy Chan 的回答,特别包括有关哪些值被视为niltrue的信息false

于 2013-09-08T15:36:53.863 回答
1

终于我得到了答案,感谢彼得的更新。

  1. 要在迁移中设置布尔值,请使用t.boolean :foo
  2. 要验证布尔值,请使用彼得回答中推荐的验证器。
  3. 要了解哪些值将用作truefalse值,请参见下文。(我认为没有必要对它们进行单元测试,尽管包含其中一部分的集成或功能测试是可以的)

我刚刚浏览了源代码。boolean 类型,无论是 PostgreSQL、Sqlite3 还是 MySQL,最终都会指向ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value),

    # convert something to a boolean
    def value_to_boolean(value)
      if value.is_a?(String) && value.empty?
        nil
      else
        TRUE_VALUES.include?(value)
      end
    end

然后被这个常数判断

  # the namespace is still "ActiveRecord::ConnectionAdapters::Column"
  TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON'].to_set
  FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set

所以,我们终于明白了。

  1. 如果为空,则无

  2. 如果不为空,检查它是否在 TRUE_VALUE,如果不是,则为 false。这就是为什么“4”、“是”是假的。

于 2013-09-09T15:27:30.100 回答