Reputation: 28189
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?
Upvotes: 18
Views: 8577
Reputation: 76774
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.
Upvotes: 5
Reputation: 106027
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
Upvotes: 12
Reputation: 2378
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
.
Upvotes: 0