Rails: Almost Automatic Client-Side Validation
December 15th, 2006 by michael
Ruby on Rails already does a good job of specifying almost declaratively what conditions objects must meet to be considered valid–that is, how they are validated.
Thus, in order to make sure that a Person’s last_name attribute does not exceed 100 characters, you would write something like this
class Person < ActiveRecord::Base validates_length_of :last_name, :maximum => 100 end
Somewhere in a view you’ll probably refer to the last_name attribute like this
<% form_for :person, @person, :url => { :action => "update" } do |f| -%>
Last name : <%= f.text_field :last_name %>
<%= submit_tag %>
<% end -%>
There you get a nice form where users can enter last names as long as they may wish–only to be shown an error message complaining about the length in cases where they have unwittingly overshot the limit. How should they have known?
Well, as a nice and caring person you could add an annotation to each input field saying how long its contents are allowed to be. That would be slightly better, but still leaves more work for the users than necessary.
How about this: Users are immediately notified in an unobtrusive way that some of the content they have (or have not yet) filled into a form does not constitute valid data. Furthermore, users are kept from submitting a form that contains obviously invalid data.
Should be easy, shouldn’t it? Yes, it should and actually it is just two plugins away.
Raising awareness of validations
Out of the box, Rails handles validations in such a way that it adds callbacks for checking them to model classes, but otherwise immediately loses awareness of them. When later on in the lifecycle of a model instance validations are checked, Rails does so on autopilot. A model class just does it’s thing, it won’t tell you what it’s doing, but you can be sure it’ll complain when something is wrong. Let’s add some reflection to make model classes a bit more loquacious. The details are irrelevant, just install the Validation Reflection plugin into your Rails application
$ script/plugin install svn://rubyforge.org//var/svn/valirefl/validation_reflection/trunk
Tell the browser
So far, the newfound awareness of validations idles away on the server-side. Somehow it has to be transported to the user’s browser. That is one of the things the Client-Side Validation plugin does. Install with
$ script/plugin install svn://rubyforge.org//var/svn/clientsidevali/client_side_validation/trunk
The first thing this plugin does is that it enhances tags generated by Rails’s helper methods in such a way that they contain encoded information about the validation constraints that apply to their values.
Engage the client
Still, even though validation information has been inserted into the HTML sent to the browser, where it lays dormant. On the client-side, JavaScript is where the action is. Therefore the task of checking validations there is handled by a validator written in JavaScript included with the Client-Side Validation plugin.
The generic script for the validator is included in your views or layout as part of the default scripts, therefore it is probably just there already.
<%= javascript_include_tag :defaults %>
Here we come to a point where you, the programmer, have to make some decisions and do some work. First, you need to decide (or have your code decide) what locale your users are in. Remember, dates don’t look the same all over the world.
<%= javascript_include_tag 'validators-en' %>
Currently English (en) and German (de) are supported.
Then, you have to tell the validator that there’s work for it to do. For this, all forms that ought to be validated have to be marked with the class validated. Thus, the above form becomes
<% form_for :person, @person, :url => { :action => "update" }, :html => { :class => 'validated' } do |f| -%>
Last name : <%= f.text_field :last_name %>
<%= submit_tag %>
<% end -%>
Also, you need to nudge the validator to start looking at the forms by adding a line to public/javascripts/application.js
Form.Validator.installForAllValidatedForms();
You ain’t see nothing yet
If you’ve followed all these steps, the validator is probably doing its work, but hardly see anything of it. You may notice that the submit button is enabled when the form is valid and disabled when it is invalid, but that is all there is.
A further, but still invisible, thing that the validator does is that it adds (removes) the class “invalid” to input elements when they are invalid. Making this change in attribute visible is a small matter of CSS
.invalid {
border: 1px solid #f00;
}
The result is not pretty, but you can push your stylesheeting abilities to the limit to make them look however you like. Also, the validator offers hooks for customizing most aspects. But that is left for a future installment.

Perhaps its worth using the same CSS element for an invalid field that the error_messages_for helper uses: fieldWithErrors
Yes, I think I’ll make the CSS error class configurable and use fieldWithErrors as the default. Thanks for the suggestion.
I intend to completely overhaul the validator code. For one thing, the code is not a clean and obvious as it should be.
Cool, I think this is a project people will benefit from. I hope to have a look at it soon.
Is there any way to get this to work with remote forms? I am trying it and it doesn’t seem to be doing anything.
Sean, I have never tried the validator with a remote form. Off hand, I think it ought to work as by itself, a “remote” form is nothing special, it is just submitted in a special way.
Does the validator work for you on an ordinary, non-remote form? That’s the first thing to make sure. Then, if it does work there, try it for a remote form. In both cases make sure that the generated form has the class attribute “validated”, i.e.
Also, the validator out of the box works only for forms present in the page as originally loaded. If you construct a form dynamically, if it is loaded in an AJAX request from a partial or RJS, then you’ll have to install the validator manually for such a form. Use
for this.
Michael, is this still under development? I’m thinking about using and possibly extending upon your auto validation plugin for our internal website.
I’d like to say yes, but in truth, I haven’t put any work into this for a long time. The best thing I can say is that it just works. So, if the plugin does what you need, give it a try. If not, well, complain to me and I’ll have a look what I can do.
.. sent you a separate email about this, didn’t notice you responded to my previous comment. Anyways, I noticed the validation only works for validates_presence_of. For _format and _length, the validations don’t seem to work (even though I see the CSS class name with the encoded info). I probably have some more debugging I need to do. But have seen this issue before?
It appears there’s a bug with the validator generator for format, where it doesn’t encode underscore correctly. If the regular expression “%r{^([a-zA-Z]+[-_]?[a-zA-Z]+)+$}” is used. The underscore would prematurely terminate the format string since it’s used as the separator.
[...] I presented yesterday is one piece in the puzzle to rejuvenate my languishing JavaScript form validator. I’ve not yet made up my mind on a lot of issues, but there’s one thing that’s [...]
Hi Michael, I read carefully your instructions and tried several times to make your useful plugin work on my app, but I when I load the page which has the form inside I get this error on the Javascript error console :
Form.Validator has no properties
I´m using a common form (meaning ) but with the form_helper I´m getting the same trouble.
Any ideas about what I´m doing wrong?
Jose, if Form.Validator has no properties, than validator.js is not loaded from your page. Either the necessary script tag is missing or the script it refers to is not installed at the correct location.
[...] rails almost automatic client side validation wow this looks cool. Re-use your rails validations client-side in javascript. [I think] link [...]
Hi, Michael.
How can I install the plugin on Windows Rails environment?
My configuration is:
Rails: 2.1.0
Ruby: 1.8.6
Gem: 1.2.0
rake: 0.8.1
/vendor/plugins/client_side_validation# ruby install.rb
install.rb:7: uninitialized constant RAILS_ROOT (NameError)
Wilton, I have no idea why RAILS_ROOT might not be defined in your case. I just created a fresh Rails 2.1 project (on Linux) and then
and it worked.
it would be better with other languages support, but thanks..
Hi Michael, the instructions seemed st-fwd, however, I get the error on console while trying to fetch the page: Is there an issue with Rails/ActiveRecord2.2.2?
ActionView::TemplateError (stack level too deep) on line #23 of app/views/………rhtml:
23: 36, :class => ‘text’ %>
/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/core_ext/hash/keys.rb:16:in `stringify_keys!’
/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/core_ext/hash/keys.rb:15:in `each’
/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/core_ext/hash/keys.rb:15:in `stringify_keys!’
…..
I get the error with or without adding html => {:class => ‘validated’} in form_for.
Any clue?
I’d have to see the place where stringify_keys! is called originally. There’s one place in my code (#add_class_name!) and although I don’t see how it might lead to an infinite recursion, you may try to comment it out.
I’ve just uploaded a new version fixing another problem with Rails 2.2.2 to Rubyforge, so please update your version before trying anything else.
Hi Michael,
thank you for the plugin! I got it working as you described — the submit button is disabled if the form is invalid. But I am not sure how to make it display the appropriate error messages as the user types. I must be missing something basic, I am new to this, please advise!
thank you,
Olia
Olia, displaying an error message is something you have to code yourself. There are just too many ways to do this and too many complications that I did not have a general solution when I wrote the validator script more than three years ago.
What you can get easily is some CSS styling for fields that have errors. See the example above.
You might be better off with another solution, however, none of the other validator scripts that I ever was aware of do everything you would want them to.
Thanks for the reply Michael!
I guess I have to do some coding, rather than trying to piece together other people’s work!
But I think I am understanding how to achieve some results with .invalid, based on your example. Needless to say, I’m new to CSS as well…
Thanks again!
Olia