30

I've got the following Model:

class GuestCatering < ActiveRecord::Base

  # Validation
  validates :name, :presence => true
  validates :order_number, :presence => true
  validates :orderable, :presence => true

end

But when I'll try to update an existing GuestCatering with the following code:

guest_catering.update_attributes(:orderable => false)

The guest catering variable is a valid GuestCatering object. The guest_catering object has errors after the update, like that:

<{[:orderable, ["can't be blank"]]=>nil}>

But when i pass a orderable => true, everything is fine and no errors.

What's wrong here, why can't i set orderable to false?

LeonS
  • 2,684
  • 2
  • 31
  • 36

3 Answers3

43

Your model is actually behaving exactly as you told it to, through your use of validates :orderable, :presence => true

There's little point validating the presence of a boolean flag - it's going to be true, nil or false - and in Ruby world, nil and false have the same semantic value when it comes to boolean logic.

Internally, validates :presence relies on the value of the attribute being checked to return false when blank? is called. And, in Rails (with ActiveSupport), false.blank? evaluates as true - which means that your field is failing the validation.

Simply remove that validation and everything will work as expected.

dnch
  • 9,565
  • 2
  • 38
  • 41
  • So I can't validate a boolean flag? – LeonS Mar 07 '11 at 12:15
  • 3
    How would you validate it? It's either on or off. If you _need_ it to be true (such as agreeing to terms), then you could use a validation to enforce it. In your case, it doesn't appear to be required. – dnch Mar 07 '11 at 12:17
  • Thanks this helped me out a lot i was in a similar predicament – Alain Goldman Dec 10 '14 at 00:30
21

Like Dan Cheail already said in his answer, a nil and false boolean is semantically the same thing.

But, if you really need to validate it (not allowing nil), you can always do :

validates_inclusion_of :orderable, :in => [true, false]

Raf
  • 1,083
  • 11
  • 15
  • If your database column for your boolean is `NOT NULL`, this is the correct answer as this will validate the field before attempting to write the record. The other answer will allow the validation to pass with `nil`, but `.save` will error on the column restriction. – dbcb Jan 24 '17 at 00:22
-2

Instead of validates :presence => :true, you should write your migrations with the default value like this:

t.boolean :orderable, :default => 0

I assume your default value should be false. If true, use 1 as default. Then it will set the default value in database. So, you can omit the validation check.

The reason you cannot use validates :presence is answered by @dan. Presence means not blank and Rails use .blank? function for this and false.blank? is true

rubyprince
  • 17,559
  • 11
  • 64
  • 104