Rails:验证包含布尔失败测试

时间:2011-03-02 15:55:34

标签: ruby-on-rails unit-testing validation boolean

我正在尝试确保我的模型的字段是布尔值,但我的测试仍然失败。

阅读完本文后:Validating boolean value in Rspec and RailsRails: how do I validate that something is a boolean?我最终这样做了:

class Model < ActiveRecord::Base

  validates :my_field, :inclusion => { :in => [true, false] }

end

我尝试过几种不同的测试方法(使用rspec和shoulda匹配器),并且由于我的测试一直在失败,我现在正处于最糟糕的可能(?)方式。仍然,测试没有通过,我猜测有一些机制可以在某处转换价值。

以下是我用来了解发生了什么的事情:

# create instance without setting value ...

# these work as expected
model_instance.valid?.should be_false      # passes
model_instance.my_field = true
model_instance.valid?.should be_true       # passes
model_instance.my_field = false       
model_instance.valid?.should be_true       # passes

# works as expected
model_instance.my_field = ""
model_instance.valid?.should be_false      # passes

# these should pass but fail
model_instance.my_field = "foo"
model_instance.my_field.should == "foo"    # fails as well, my_field == false
model_instance.valid?.should be_false      # fails

model_instance.my_field = "false"
model_instance.my_field.should == "false"  # fails as well, my_field == false
model_instance.valid?.should be_false      # fails

model_instance.my_field = "123"
model_instance.valid?.should be_false      # fails

model_instance.my_field = "true"
model_instance.my_field.should == "true"   # fails as well, my_field == true
model_instance.valid?.should be_false      # fails

我错过了什么? 似乎价值是以某种合乎逻辑的方式转换但是在哪里以及如何防止它?如何正确地进行这种验证?

2 个答案:

答案 0 :(得分:36)

我不知道你需要将一个布尔字段验证为true / false的想法来自哪里,但我最近在一些不相关的项目中看到过它,所以我开始怀疑这是不是一个从某个地方开始的模因。

它是一个布尔字段,它必须是真或假。 AR负责处理布尔值的实现细节。如果需要布尔字段,请在数据库中创建一个布尔字段。故事结局。

查看源代码,这里是将值转换为布尔值的代码:

# File activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb, line 147
147:         def value_to_boolean(value)
148:           if value.is_a?(String) && value.blank?
149:             nil
150:           else
151:             TRUE_VALUES.include?(value)
152:           end
153:         end

这里的值等同于它们的布尔对应物:

TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set

所以再看一下上面的代码,一切都是应该的,除了你期望的是不正确的。将“foo”赋给布尔值我们看到“foo”不在可接受的真值列表中,因此布尔字段默认为false,这是它稍后将从其访问器返回的值。该字段的布尔值仍为:in => [true, false],因此模型有效。出于同样的原因,“假”和“123”失败了。 “true”是布尔值true的可接受值,因此该字段设置为true,并且由于上述原因仍然有效。

答案 1 :(得分:27)

我不是Rails大师,但是我会把我的脖子伸到这里并说你绝对想要验证:inclusion => { :in => [true, false] }的布尔值 - 也就是说,假设你不想允许nil(NULL) )值。

来自数据库编程背景,我已经学会记住布尔字段可以有三个值:true,false和NULL。在本机SQL中编程时,NULL需要特殊处理(is null而不是= null),这会导致大量额外工作。

在今天使用Rails 3.2进行测试时,创建一个带有nil值的未经验证的布尔字段并将其保存到我的PostgreSQL数据库并将其尽职地存储为NULL是没有问题的。为了避免可能引起的所有问题,我打算在Rails中使用这种方法来处理布尔值:

  • 在迁移中使用:null => false定义布尔字段。
  • 使用:inclusion => { :in => [true, false] }验证模型中的字段。如果字段未初始化(nil),这会给出一个很好的消息。

一开始并不直观,我无法使用:presence验证,但事实证明:presence验证了值不为空,值为false 空白。换句话说,如果您验证:presence => true并将值设置为false,则验证将失败。请参阅API中的validates_presence_of和@Paul A Jungwirth关于@ Karmajunkie答案的评论。