Multiple validations on a field... grouping them? only one?

Hello!

Has anyone come across a nice, elegant way to handle multiple
validation failures on a single field? For example… in the typical
login, you might have an email field that has three validations: not
blank, less than a max length and matches a format regex. But if I
submit the login/signup form with a blank I get back:

Email address is too short (minimum is 6 characters)

Email address should look like an email address.

Email address can’t be blank

I’d rather be able to specify (cleanly and easily) on a model some
kind of order of importance and then only show the first validation
failure for that field.

Thoughts? Advice?

TIA!

-Danimal

Danimal wrote:

Hello!

Has anyone come across a nice, elegant way to handle multiple
validation failures on a single field? For example… in the typical
login, you might have an email field that has three validations: not
blank, less than a max length and matches a format regex. But if I
submit the login/signup form with a blank I get back:

Email address is too short (minimum is 6 characters)

Email address should look like an email address.

Email address can’t be blank

I’d rather be able to specify (cleanly and easily) on a model some
kind of order of importance and then only show the first validation
failure for that field.

Why? As a user, I find it extremely annoying when I fix one validation
error, submit the form, and get shown a different error. I’d rather see
all the validation errors at once so I can fix them all at the same
time.

Thoughts? Advice?

Don’t do that. :slight_smile:

TIA!

-Danimal

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Jan 12, 2010, at 4:51 PM, Danimal wrote:

Email address can’t be blank

I’d rather be able to specify (cleanly and easily) on a model some
kind of order of importance and then only show the first validation
failure for that field.

Thoughts? Advice?

TIA!

-Danimal

These all seem to be aspects of the same thing. If an email looks
like an email address, then it is presumably at least 6 characters
([email protected]
) and thus non-blank.

validates_format_of :email_address,
:with => /\A([^@\s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})\z/i,
:message => ‘should look like an email address’

or even some more sophisticated expression. You could toss
in :allow_nil=>false or :allow_blank=>false even though the default
for both is already false.

You could write your own validate() method and take over all the
validation, but that might not be a viable option if there are several
fields with validations.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

I have to agree with both Marnen and Rob here.

First, validations are not meant to make a user happy. It’s to ensure
that proper validation is met before data is inserted into your
database. Therefore, the more accurate you validate your forms, the
least likely you are to have some type of data corruption occur within
your tables. It is much easier to review all of the validations taking
place than to specify for specific entries because more than one could
be incorrect.

Second, you can definitely write your own validations but keep some
things in mind when you do so. If you are going to reuse the validation
(most likely you are) place it in your initializers so that your
environment remains clean and you also can reuse the validator at some
point in time.

I have the following custom validator located in validators.rb in my
config -> initialize folder.

In the example below, this custom validation is making sure that two
fields are identical.

def self.validates_is_exact(attr_names)
options = attr_names.extract_options!
validates_each(
(attr_names << options)) do |record, attr_name, value|
if record.send( options[:compare_field] ) != value
record.errors.add(attr_name, options[:message])
end
end
true
end

validates_is_exact :field_one, :compare_field => :field_two

I hope that helps answer your question.

Rob B. wrote:

On Jan 12, 2010, at 4:51 PM, Danimal wrote:

Email address can’t be blank

I’d rather be able to specify (cleanly and easily) on a model some
kind of order of importance and then only show the first validation
failure for that field.

Thoughts? Advice?

TIA!

-Danimal

These all seem to be aspects of the same thing. If an email looks
like an email address, then it is presumably at least 6 characters
([email protected]
) and thus non-blank.

validates_format_of :email_address,
:with => /\A([^@\s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})\z/i,
:message => ‘should look like an email address’

or even some more sophisticated expression.

Please don’t use a more sophisticated expression. The only such
correct regexps I’m aware of for e-mail addresses are on the order of
a page in length. An incorrect regexp will reject valid e-mail
addresses (this actually happens surprisingly frequently). Just check
for the @ and . and trust the user for the rest.

You could toss
in :allow_nil=>false or :allow_blank=>false even though the default
for both is already false.

You could write your own validate() method and take over all the
validation, but that might not be a viable option if there are several
fields with validations.

In the latter case, it’s easy to write custom validators.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Alpha B. wrote:

I have to agree with both Marnen and Rob here.

First, validations are not meant to make a user happy. It’s to ensure
that proper validation is met before data is inserted into your
database.

Not really. Validations are meant to make users happy, sort of. The
database should have its own check and key constraints so that invalid
data can never make it in there.

App-layer validations exist so that the app UI can be better and so that
complex constraints that are impractical to put in the DB are possible
(such as e-mail regex validation?).

Therefore, the more accurate you validate your forms, the
least likely you are to have some type of data corruption occur within
your tables.

No! You must not rely solely on Rails validations to prevent your
database from getting corrupted.

It is much easier to review all of the validations taking
place than to specify for specific entries because more than one could
be incorrect.

Yes.

Second, you can definitely write your own validations but keep some
things in mind when you do so. If you are going to reuse the validation
(most likely you are) place it in your initializers so that your
environment remains clean and you also can reuse the validator at some
point in time.

Again, no. Put it in a module or something, same as you would any other
AR class method.

I have the following custom validator located in validators.rb in my
config -> initialize folder.

That should be in a module, probably in your lib folder. You could call
it from a plugin, or use environment.rb or an initializer to include it
in AR::Base.

In the example below, this custom validation is making sure that two
fields are identical.

def self.validates_is_exact(attr_names)
options = attr_names.extract_options!
validates_each(
(attr_names << options)) do |record, attr_name, value|
if record.send( options[:compare_field] ) != value
record.errors.add(attr_name, options[:message])
end
end
true
end

validates_is_exact :field_one, :compare_field => :field_two

Bad example. The only time you should ever need to do this is in the
case already covered by validates_confirmation_of. If you have two
fields in the DB that should always be identical, then remove one of
them.

I hope that helps answer your question.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Alpha B. wrote:

Marnen Laibow-Koser wrote:

Bad example. The only time you should ever need to do this is in the
case already covered by validates_confirmation_of. If you have two
fields in the DB that should always be identical, then remove one of
them.

I’m sorry, but I have to disagree. In the case my example, I referred
to an example of virtual pages versus hard controller pages. In the
case of matching fields, if a controller redirect occurs to a statically
created page, I want the name field and the controller field to be exact
because of meta data creation in quite a few areas. However, in the
case of a virtually created (dynamic) page where redirects are not
occurring, the controller field is not used and the name field is.
Therefore, you would not use a controller field for a virtually created
page.

What do you mean by “hard controller pages”? If I understand correctly,
I think you are making an artificial distinction that is impeding your
design decisions.

So, no, you would not destroy another field that serves a
completely different and unique purpose.

If the two fields serve independent, unique purposes, then they will
contain different data some of the time. If they can never, ever
contain different data, then they are ipso facto not independent and
should be merged.

It’s that simple.

It’s very easy to provide a simple no to a question but before you do,
you should understand what you are saying no to.

I do.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Marnen Laibow-Koser wrote:

Bad example. The only time you should ever need to do this is in the
case already covered by validates_confirmation_of. If you have two
fields in the DB that should always be identical, then remove one of
them.

I’m sorry, but I have to disagree. In the case my example, I referred
to an example of virtual pages versus hard controller pages. In the
case of matching fields, if a controller redirect occurs to a statically
created page, I want the name field and the controller field to be exact
because of meta data creation in quite a few areas. However, in the
case of a virtually created (dynamic) page where redirects are not
occurring, the controller field is not used and the name field is.
Therefore, you would not use a controller field for a virtually created
page. So, no, you would not destroy another field that serves a
completely different and unique purpose.

It’s very easy to provide a simple no to a question but before you do,
you should understand what you are saying no to.

Marnen Laibow-Koser wrote:

If the two fields serve independent, unique purposes, then they will
contain different data some of the time. If they can never, ever
contain different data, then they are ipso facto not independent and
should be merged.

It’s that simple.

The two fields serve independent, unique purposes, and they contain
different data. The only time I check for validation for exact data is
when the page being created calls a redirect to a controller - action.
In this case, I require the name and the controller to be exact for too
many reasons to explain or to go into this particular topic.

The point I was making is that you can’t generalize a topic and correct
people on criteria you have no information about. You are making false
assumptions. If you saw all of my code you could make an informed
reply.

Validation is a tricky topic and there are many reasons people create
custom validations. The point I was making is that it can be done and
to make sure you don’t muddy up the place you put your custom
validators. I understand your point on putting it in a module. I
disagree but in this case we can agree to disagree on the topic.

Thanks.

Alpha B. wrote:

Marnen Laibow-Koser wrote:

If the two fields serve independent, unique purposes, then they will
contain different data some of the time. If they can never, ever
contain different data, then they are ipso facto not independent and
should be merged.

It’s that simple.

The two fields serve independent, unique purposes, and they contain
different data. The only time I check for validation for exact data is
when the page being created calls a redirect to a controller - action.
In this case, I require the name and the controller to be exact for too
many reasons to explain or to go into this particular topic.

Then in this case, you’re right, a validation makes sense.

The point I was making is that you can’t generalize a topic and correct
people on criteria you have no information about. You are making false
assumptions. If you saw all of my code you could make an informed
reply.

And if you had explained the situation more fully in the first place, I
would have been able to do that. :slight_smile:

Validation is a tricky topic and there are many reasons people create
custom validations. The point I was making is that it can be done and
to make sure you don’t muddy up the place you put your custom
validators. I understand your point on putting it in a module. I
disagree

Why do you disagree?

but in this case we can agree to disagree on the topic.

But we shouldn’t. If you have a good reason, I’d like to hear it.

Thanks.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Marnen Laibow-Koser wrote:

But we shouldn’t. If you have a good reason, I’d like to hear it.

It’s a personal preference. Some people put custom validators in libs
and others do it in initializers.

I decided to use initializers more because it makes sense for validators
and also because I had originally learned to do so right here:

http://guides.rubyonrails.org/activerecord_validations_callbacks.html

According to rubyonrails.org right in their
activerecord_validations-callbacks they state:

============= QUOTE from rubyonrails.org ==================
You can even create your own validation helpers and reuse them in
several different models. Here is an example where we create a custom
validation helper to validate the format of fields that represent email
addresses:

ActiveRecord::Base.class_eval do def self.validates_as_radio(attr_name,
n, options={}) validates_inclusion_of attr_name, {:in =>
1…n}.merge(options) end end

Simply reopen ActiveRecord::Base and define a class method like that.
You’d typically put this code somewhere in config/initializers.

===========================================================

Some items don’t need to go into initializers but again, it’s more of an
organizational approach to rails and if you can show me 100% that both
rubyonrails.org and me are wrong, please do so.

Thanks mate. :slight_smile:

ActiveRecord::Base.class_eval do

def self.validates_is_exact(attr_names)
options = attr_names.extract_options!
validates_each(
(attr_names << options)) do |record, attr_name,
value|
if record.send( options[:compare_field] ) != value
record.errors.add(attr_name, options[:message])
end
end
true
end

end

=========

Read the post above Marnen, but for thoroughness, I’m supplying the code
I have in my initializers folder for validators.rb. This way you can
see what I’m doing precisely.

Take care mate.

Alpha B. wrote:

Marnen Laibow-Koser wrote:

But we shouldn’t. If you have a good reason, I’d like to hear it.

It’s a personal preference. Some people put custom validators in libs
and others do it in initializers.

I decided to use initializers more because it makes sense for validators
and also because I had originally learned to do so right here:

http://guides.rubyonrails.org/activerecord_validations_callbacks.html

According to rubyonrails.org right in their
activerecord_validations-callbacks they state:

============= QUOTE from rubyonrails.org ==================
You can even create your own validation helpers and reuse them in
several different models. Here is an example where we create a custom
validation helper to validate the format of fields that represent email
addresses:

ActiveRecord::Base.class_eval do def self.validates_as_radio(attr_name,
n, options={}) validates_inclusion_of attr_name, {:in =>
1…n}.merge(options) end end

Simply reopen ActiveRecord::Base and define a class method like that.
You’d typically put this code somewhere in config/initializers.

===========================================================

Some items don’t need to go into initializers but again, it’s more of an
organizational approach to rails and if you can show me 100% that both
rubyonrails.org and me are wrong, please do so.

Interesting. I wasn’t aware that that was in the guides. My
interpretation from reading the guide, however, is that while that may
be good for the case described in the guide – one custom validator only
– you really wouldn’t want to do it for anything more involved. I
think having long initializer files is probably a code smell in most
cases.

Frankly, I think even for one custom validator this is probably a bad
idea. I think whoever wrote that part of the guides really dropped the
ball, unless he or she was simply trying for initial simplicity without
elegance.

Also, I think you’re cookbooking the guides a little too much – that
is, taking their solutions as gospel even for cases they didn’t really
consider. You’ll note that the guide never mentions the case of
multiple validators. Remember, sample code is just that – sample code,
not scripture.

In short: I see good reasons not to do it the way the guide does –
it’s sloppy and duplicates Ruby’s module system for no good reason. I
see not a single good reason to do it the way the guide does.

Do you have such a reason, other than “because the guide says so”?

Thanks mate. :slight_smile:

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs