sudo bangbang
sudo bangbang

Reputation: 28189

To validate or not to validate boolean field

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

Answers (3)

Richard Peck
Richard Peck

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

Jordan Running
Jordan Running

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

yez
yez

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

Related Questions