Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #3334 (new defect)

Opened 4 years ago

Last modified 2 years ago

[PATCH] A false value for a boolean field fails validates_presence_of

Reported by: James Assigned to: core
Priority: normal Milestone:
Component: ActiveRecord Version: 1.0.0
Severity: normal Keywords: validates_presence_of false allow_false
Cc: tarmo

Description

If you have a boolean field in a database (in this case PostGres 8.1) and you try to use the validates_presence_of it fails if the value to be inserted is the constant false.

Attachments

ar_validates_presence_of_for_boolean_fixed_with_tests.diff (2.6 kB) - added by sur on 09/05/07 08:41:04.
resubmitting the updated path and tests as the ticket 9392 is fixed.

Change History

02/07/06 02:08:39 changed by anonymous

That happens because validates_presence_of checks attributes with "blank?", nil, false and empty strings are all considered blank. Not sure though if this validation should not be used at all or if it should actually check only that the attribute would not be nil.

03/27/06 20:50:29 changed by work@ashleymoran.me.uk

I noticed this recently, and without looking at the source I assumed it just tests "if variable" rather than "if !variable.nil?". I suppose if the database has a not-null constraint, and the interface only presents true and false options (and not N/A) then you would never be able to insert an invalid value. On the other hand I don't like not being able to specify validates_presence_of just for completeness.

04/08/06 00:08:01 changed by ebrandeis@gmail.com

I ran into this problem today. I think it is worth distinguishing between TRUE, FALSE, and NIL for booleans and allowing validates_presence_of. While the select box should always provide a valid True/False value, a bug in the code somewhere could try to save a model to the database without setting a field that should have a guaranteed TRUE or FALSE. Without validates_presence_of available for booleans, it seems that this could slip by.

05/03/06 14:20:39 changed by pfortuny@gmail.com

Yes, this happens also in mysql, for the record.

08/17/06 02:25:56 changed by anonymous

This is problem becomes even worse if the field's column is defined to be non-null (at least in mysql) because then the field gets initialized with a value, but the user may not have selected one yet.

The same problem applies to floats, and ints.

As far as I know, there is no work around for boolean and floats to validate that they were entered with non-null columns.

01/13/07 04:47:53 changed by manfred

  • status changed from new to closed.
  • resolution set to wontfix.

This is intended behavior and documented with the validation method.

From the documentation:

If you want to validate the presence of a boolean field (where the real values are true and false), you will want to use validates_inclusion_of :field_name, :in => [true, false]. This is due to the way Object#blank? handles boolean values. false.blank? # => true}

08/22/07 04:19:40 changed by tarmo

  • cc set to tarmo.
  • status changed from closed to reopened.
  • resolution deleted.

manfred, are you sure it's the intended behaviour?

The documentation snippet seems to be saying: "validates_presence_of does not work because it's implemented in the wrong way". But why can't it be fixed?

One possible fix is this:

Index: lib/active_record/validations.rb
===================================================================
--- lib/active_record/validations.rb	(revision 7353)
+++ lib/active_record/validations.rb	(working copy)
@@ -79,7 +79,8 @@
     def add_on_blank(attributes, msg = @@default_error_messages[:blank])
       for attr in [attributes].flatten
         value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
-        add(attr, msg) if value.blank?
+        add(attr, msg) if value.blank? && value != false
       end
     end

But it makes test_validate_presences test fail because the test sets a serialized attribute to a string that contains only spaces. This string, when sent through YAML::load will be turned into 'false' which validates_presence_of with the fix does let through.

So does that mean that validates_presence_of can not properly validate boolean values because it would break serialized attributes that use validates_presence_of and that get set (for no apparent reason) an empty string as a value? Why should an empty string, when unserialized be turned into 'false' instead of 'nil' or perhaps even, an empty string?

08/22/07 06:14:59 changed by manfred

I primarily closed the ticket because it's documented behaviour, not specifically because I think it's the right behaviour. I remember some sort of problem with changing the validation, but I can't really recall what it was. Maybe somebody else's memory about this is better than mine?

08/22/07 06:21:05 changed by manfred

Ah, I remember why you're proposed solution doesn't work. If you allow false as a non-blank value, you also allow false on other column types like text and integer.

08/22/07 12:20:28 changed by tarmo

Assigning false to an integer column seems to convert it to 0 so that does not seem to be a problem but assigning it to a text column:

007:0> x.first_name=false
false
008:0> x.first_name
false
009:0> x.valid?
NoMethodError: undefined method `size' for false:FalseClass
	from /usr/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/validations.rb:493:in `validates_size_of'

(NOTE this is with rails 1.2.3 without my proposed change)

So integer is not really a problem or if it is then integer columns themselves behave in a wrong way (by accepting false and converting it to 0). And text columns, well, validates_presence_of may work on them if they get set to false, but validates_size_of certainly does not, so whats the point? And actually there really is no way to actually set a false value to a text column (as a browser can only send text) so I can't see why this is something that should be specifically validated cause it can basically only be an error in the application code not in what the user submits.

08/25/07 18:32:52 changed by sur

more logical as assignment to integer converts true/false into 1/0 .. assignment to string should convert it into "true" and "false" and reader methods somehow back to true/false.

08/27/07 06:42:43 changed by sur

  • summary changed from A false value for a boolean field fails validates_presence_of to [PATCH] A false value for a boolean field fails validates_presence_of.

this patch modifies the validates_presence_of for boolean attributes to accept the false value by specifying...

validates_presence_of :is_published, :allow_false => true

Test case added for the modification. Tested for mysql, all existing test cases and the new are running fine.

09/05/07 08:41:04 changed by sur

  • attachment ar_validates_presence_of_for_boolean_fixed_with_tests.diff added.

resubmitting the updated path and tests as the ticket 9392 is fixed.

09/05/07 10:00:07 changed by sur

added updated patch in context with the ticket 9392

09/05/07 18:08:30 changed by sur

  • keywords changed from validates_presence_of false to validates_presence_of false allow_false.
  • owner changed from David to core.
  • status changed from reopened to new.