15
votes

Is there any benefit in having validations for boolean fields of models?

I had a validation for ensuring the presence of a boolean field

validates :boolean_attribute, presence: true

It failed when boolean_attribute was false. I googled around and found these SO questions relating to the issue.

Rails database defaults and model validation for Boolean fields
Rails validates_presence not validating on Boolean?

Then added this validation instead

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

This made me think. Do I need any validations for boolean fields at all? Its value will always be true or false or nil right? Even if someone maliciously try to change it to say, a number, wouldn't the type take care of it? Or is there some safety the above inclusion validation provides?

3
yeah, I usually don't bother. If the field is mandatory - you can use the inclusion-in trick above, and to be sure put null: false on the columnTaryn East
If you need the value to be true or false but not nil then you want to use the validation. If true, false, and nil are all okay, you don't need the validation. Which of those is correct for you depends entirely on your use case.Jordan Running
@Jordan: I'm cool with nil as long as ruby validates it to false and there are no scenarios that might break the system. Are there any?sudo bangbang

3 Answers

11
votes

Whether or not you should validate a boolean attribute for inclusion in [ true, false ] depends entirely on your use case.

You've correctly identified that, in the absence of validation of other code, a boolean field in Rails will always be (after type coercion) true, false, or nil. Rails won't coerce nil to false. If you set a model's boolean attribute to nil and save it, the attribute will be nil, not false, when you fetch the it from the database later.

You can think of nil as a "third state" for a boolean field. Consider a simple survey app that lets users save an unfinished survey to complete later. Suppose a user saves an incomplete survey with the question "Do you eat meat?" unanswered. You don't want to store false in the database because that would indicate that the user answered "no." When the user comes back to finish the survey you want that question to still be unanswered, so you want to store nil in the database.

In cases like the above, it's appropriate (and necessary) not to validate for inclusion in [ true, false ].

However, as a rule of thumb I would say that in all other cases—i.e. in any case where you don't have a specific need for nil values—you should validate boolean fields for inclusion in [ true, false ].

Of course, if you do allow nil you'll need to be careful because, as you know, nil is a falsey value in Ruby. You'll have to explicitly check for "nilness" in places where you might otherwise rely on a value's truthiness or falsiness. That is, instead of this:

if !is_meat_eater
  unanswered_questions << :is_meat_eater
end

...which will not behave as intended if is_meat_eater is false, you'll need to explicitly check for nil:

if is_meat_eater.nil?
  unanswered_questions << :is_meat_eater
end
5
votes

You don't need to validate a boolean field, if it's not true it's false.

Just set a "default" in your db so that the bool is always going to have a certain value no matter what:

#db/migrate/add_boolean_column_______.rb
class AddBooleanColumn < ActiveRecord::Migration
   def change
      change_table :table do |t|
         t.boolean :field, default: false
      end
   end
end 

This way, I wouldn't even include any validations. The system will ensure you're either setting it as true or false - which is up to you as the developer.

0
votes

If you want real type validation, I'd say check out the validates_type gem. It will conduct validation on your attribute before type coercion. Type coercion can have some unexpected behaviour, this answer shows how only a certain set of values is "truthy".

If you accept a Boolean to be nil, that's not really a Boolean right? That's either true, false or a third value, nil.