Rails: Validating inclusion of a boolean fails tests

后端 未结 2 1839
小蘑菇
小蘑菇 2020-12-03 05:14

I\'m trying to ensure that a field of my model is a boolean, but my tests keep on failing.

After reading this: Validating boolean value in Rspec and Rails and this

相关标签:
2条回答
  • 2020-12-03 05:55

    I'm no Rails guru but I'll stick my neck out here and say that you absolutely do want to validate boolean values for :inclusion => { :in => [true, false] }--that is, assuming you do not want to allow nil (NULL) values.

    Coming from a database programming background, I've learned to keep in mind that a boolean field can have THREE values: true, false, and NULL. When programming in native SQL, NULLs require special handling (is null instead of = null) that causes a lot of extra work.

    In testing with Rails 3.2 today, it was no problem to create an unvalidated boolean field with a nil value and save it to my PostgreSQL database, where it was dutifully stored as NULL. To avoid all the problems that would cause, I'm planning on using this approach for booleans in Rails:

    • Define boolean fields with :null => false in migrations.
    • Use :inclusion => { :in => [true, false] } to validate the field in the model. This gives a nice message if the field is uninitialized (nil).

    It's not intuitive at first that I can't use a :presence validation, but it turns out :presence validates that the value is not blank, and the value false is blank. In other words, if you validate :presence => true and set the value to false, the validation will fail. See validates_presence_of in the API and @Paul A Jungwirth's comment on @Karmajunkie's answer.

    0 讨论(0)
  • 2020-12-03 06:18

    I don't know where this idea that you need to validate a boolean field as true/false came from, but i've seen it in a few unrelated projects recently so I'm starting to wonder if this isn't a meme that started somewhere.

    Its a boolean field, it HAS to be true or false. AR takes care of the implementation details of boolean values for you. If you want a boolean field, create a boolean field in the database. End of story.

    Looking at the source, here's the code that converts a value to a boolean:

    # 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
    

    And here are the values that equate to their boolean counterparts:

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

    So taking another look at your code above, everything is as it should be, except that what you're expecting is incorrect. assigning "foo" to a boolean value we see that "foo" is not in the list of acceptable true values, so the boolean field defaults to false, which is what it will return from its accessor later. The boolean value for the field is still :in => [true, false] so the model is valid. "false" and "123" fail for the same reason. "true" is an acceptable value of the boolean true, so the field gets set to true and is still valid for the reason outlined above.

    0 讨论(0)
提交回复
热议问题