Length validation error

I have a model that includes the following:

    validates_presence_of :zipcode     validates_numericality_of :zipcode, :plus4, :allow_nil=>true     validates_length_of :zipcode, :is=>5, :allow_nil=>true     validates_length_of :plus4, :is=>4, :allow_nil=>true

The allow_nils are just to prevent the reporting of the same error (say, a missing zipcode) multiple ways. The problem is that, when the user enters data into the form:

    <%= f.label :zipcode %>:     <%= f.text_field :zipcode, :maxlength=>5 %>-<%= f.text_field :plus4, :maxlength=>4 %>

the validation reports:

    Zipcode is the wrong length (should be 5 characters)

even when the input *is* five digits (e.g. "99999"). What's going on here?

validates_presence_of :zipcode validates_length_of :zipcode :allow_nil => true

I can hold two competing ideas in my head at one time but I don't think that's how code works...

Seriously though, it works fine here:

/auth-1.9 821 > script/about About your application's environment Ruby version 1.9.1 (powerpc-darwin9.8.0) RubyGems version 1.3.5 Rack version 1.0 Rails version 2.3.4 Active Record version 2.3.4 Active Resource version 2.3.4 Action Mailer version 2.3.4 Active Support version 2.3.4 Application root /Users/rick/auth-1.9 Environment development Database adapter postgresql Database schema version 20091111184210

Sure the code you've got matches what you've reported?

Yup. I did some googling around, and other people have apparently had problems validating the length of numbers with validates_length_of as well. No one seems to have filed a bug report about it, though.

I ended up replacing the validations with validates_format_of, and that's working for now. I'll file a bug report in the next day or so, since validates_length_of should either "just work," or be documented as being only for strings.

> Sure the code you've got matches what you've reported?

Yup. I did some googling around, and other people have apparently had problems validating the length of numbers with validates_length_of as well. No one seems to have filed a bug report about it, though.

I ended up replacing the validations with validates_format_of, and that's working for now. I'll file a bug report in the next day or so, since validates_length_of should either "just work," or be documented as being only for strings.

The length of a number isn't really a well defined concept (to me at least), For example is 1236548 a number of length 7 (because it has 7 decimal digits, of length 6 because in hex it requires 6 digits or 3 because its binary representation has 3 bytes? If what you really want is a range of numbers then validates_numericality_of has options like greater_than and greater_than

Fred

you are giving :maxlength=>5 in form rite? y cant u give the :maximum => 5 in ur model , dat would wrk i think so.

u can use :maximum => 5 in ur model instead of using dat in the form

I just want it to validate the number of digits. Since it won't do that, I used a regex instead. It's still undocumented behavior, though, which makes it a bug. :slight_smile:

No, it wouldn't. How would that validate that a number is exactly 5 digits long? If someone puts in only 4, then it's still an error.

The only way to do it currently, as far as I can tell, is with a regex like so:

    validates_format_of :zipcode, :with => /\d{5}/

validates_length_of is clearly broken (or improperly documented) in 2.3.4. Luckily, there's more than one way to achieve the same validation in this particular instance.

Is it a string or numeric field in the db?

Colin

It's an integer.

I think that is the problem, as noted earlier validates_length_of does not really make much sense for an integer. How many digits in 0123 for example? It has four digits but will be stored in the db as 123 so will no longer have four digits when you read it back. Use validates_numericality_of, specifying a range, to check it is an integer in the required range. Whether integer is the right field type for zipcode is another matter. If you needed to go international you would find that often they are not numbers.

Colin

So, based on the what all (particularly Fred) have said...

1) The easiest fix is to treat the zip code and plus4 as strings. After all, do you plan on using them as arithmetic values? This has the unfortunate byproduct of allowing "00000" "0000" as valid fields.

2) If you do continue with the fields as integers, you could validate with:

validate_numericality_of :zip_code :only_integer => true,    :greater_than_or_equal_to 00000,    :less_than_or_equal_to 99999

Both cases have the unfortunate result of allowing non-zips and non- plus4s (in terms of USPS rules) into your database. I think you would be better off to extend your model to acquire the street address from the user and ask USPS for the valid zip and plus4.

See: ZIP Code™ Lookup | USPS

Is it a string or numeric field in the db?

It's an integer.

I think that is the problem, as noted earlier validates_length_of does not really make much sense for an integer. How many digits in 0123 for example? It has four digits but will be stored in the db as 123 so will no longer have four digits when you read it back. Use validates_numericality_of, specifying a range, to check it is an integer in the required range. Whether integer is the right field type for zipcode is another matter. If you needed to go international you would find that often they are not numbers.

Colin

Depending on how you get the integer out of that string, it might be considered octal.

"0123".to_i

=> 123

Integer("0123")

=> 83

As Colin points out, a "ZIP code" is not a number (and a "postal code" even less so) as the leading zeros and the USA's ZIP+4 extension. If you stop thinking about the field as a number just because it is frequently made up of digits, you'll likely have an easier time of it.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

Validates_length_of is checking the .size property of the field; if it's already been converted to an integer, that returns the size (in bytes) not the number of digits.

The above validates_format_of isn't going to work on a repeat save, as a zipcode of '01234' will be saved to the DB as 1234, and (unless you're doing formatting not shown here) cause the validation to fail.

I tend to agree - zip codes aren't really numbers, even if they look like them. And if you implement them as strings, you won't even break a sweat when your boss comes in and says, "now we need to support CANADA!"... :slight_smile:

--Matt Jones