Skip to main content

Autovalidation with Rails

Posted by bleonard on April 16, 2008 at 12:31 PM PDT

Actually, I don't know what this feature is called, but I love it when a web application gives me instant feedback on the validity of my entry. For example:

This is especially true when I'm registering a new user account - submitting the page over and over again because the username I've selected is already taken or the password doesn't meet the requirements is always a drag.
So I started looked for examples on how to do this in Rails and couldn't really find anything (possibly because I don't actually know what to call it) - I guess it's most similar to autocompletion, so I'm going with autovalidation. And here are the steps I've put together to get it to work...

Setting Things Up

  1. Download and install MySQL.
  2. Download and install NetBeans 6.1 RC1 or later.

Creating the Rails Project

  1. Create a new Ruby on Rails Application named autovalidation. You can select Finish after the first page of the New Ruby on Rails Application dialog:

  2. Right-click the project and select Run Rake Task > db > create:

  3. Right-click the project and select Generate. Generate a scaffold with the Model Name User and the Attribute Pairs username:string:

  4. Right-click the project and select Migrate Database > To Current Version.

  5. Open user.rb and type the following:

    - this will expand to:

    type username over the attribute and press enter.

  6. On the next line in user.rb type the following:

    vl[tab] this will expand to:

    type username over the attribute and press enter. Type 5..10 over the 3..20 and press enter. The completed code should look as follows:

    class User < ActiveRecord::Base
      validates_uniqueness_of :username
      validates_length_of :username, :within => 5..10

Traditional Server Side Validation

  1. Run the project and browse to http://localhost:3000/users. Try to create a new user such as bill:

  2. Okay, create william.

  3. Try to create william again:

    Let's enhance this application with more user friendly "autovalidation"...

Lets Autovalidate

In addition to the server side validation that's being performed, we're going to add some client side validation using Ajax. We'll do this by displaying a message to the right of the field on the validity of what's been entered. Since we're validating against the database, we will need to make an XMLHTTPRequest back to the server. We can use Rails' observe_field helper method for this task.

  1. First we need to create a named placeholder for the message. Open new.html.erb and add a tag after the text field as follows:

    <%= f.text_field :username %>
  2. Now we'll use Rails' observe_field method to watch changes to that field. Add the following before the closing <% end %> tag:

        <%= observe_field   :user_username,                         # The field to observe
                            :with       => "username",              # The input to validate
                            :frequency  => 0.25,                    # The frequency in seconds to watch for changes
                            :url        => {:action => :validate }, # The action to call when changes occur
                            :update     => :message                 # The DOM ID to update

  3. Create the validate action. Open users_controller.rb and add the following:

      def validate
        color = 'red'
        username = params[:username]
        if username.length < 5
          message = 'Too short'
        elsif username.length > 10
          message = 'Too long'
          user = User.find_all_by_username(username)     
          if user.size > 0       
            message = 'Taken'    
            message = 'Available'
            color = 'green'
        @message = "#{message}"
        render :partial=>'message'

    You'll notice in the last line of the validate action above we're rendering a partial. This partial, which we'll create next, will be dynamically rendered inside the span tag we defined in step 1 above.

  4. Create a new ERB file named _message in Views > users. Replace its contents with the following:

    <%= @message %>

  5. Open users.html.erb and add the following before the closing tag:

    <%= javascript_include_tag 'prototype'  %>
    All Rails applications come with the prototype and scriptaculous libraries ready to use, but you do need to tell the application that you want to use them.

Run with Autovalidate

  1. Switch to the browser and start creating a new user (you'll need to refresh the browser once to load the prototype JavaScript libraries):


Firebug is your friend for troubleshooting Rails applications. With Firebug enabled, you can see the requests as you type:

A couple of things that tripped me up

Forgetting to include the Prototype libraries:

Misspelling the field to observe:


The Completed Application

Related Topics >>


Sorry Neil, no idea. Did you try to run the attached project to see if you get the same result? /Brian

Brian, this looks great, I'm just struggling with a weird result in which the update seems to be rendering an entirely new body tag within the span. I can see the validate requests working, it just seems to being putting a whole new request inside the span...any ideas on how to fix this?

Thanks Brian. I downloaded the project - there were a couple of differences between the code in the zip and the tutorial (the span id="message" had a couple of characters inside, and the :validate action had a 'puts #{user.username}" which wasn't in the tutorial). I realised that my user controller was running a before filter (a require login) which obviously prevented the ajax request from working (doh). I didn't check to see if it was this specifically (I didn't make a comparison between the code in the tutorial and the download, but I'm 99% sure it was my before filter). Would you like me to send you a zip with the exact code from the tutorial?

Usually will work. No worries, I've just uploaded your version of the project. Thanks!

Brian, I couldn't work out how to contact you on email so, I've uploaded it somewhere; I had to quickly go over it again because I had it set up for sqlite (really easy db setup with Rails, now the default for the framework) but I'm confident it's good to go.

Sure, send me an updated zip and I'll post it to the site. /Brian