我正在尝试确保我的模型的字段是布尔值,但我的测试仍然失败。
阅读完本文后:Validating boolean value in Rspec and Rails和Rails: 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
我错过了什么? 似乎价值是以某种合乎逻辑的方式转换但是在哪里以及如何防止它?如何正确地进行这种验证?
答案 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答案的评论。