In this post you will see how to do client side validation with jQuery in a Ruby on Rails application. The post assumes you have some knowledge of Ruby on Rails views and jQuery selectors.

We will validate a typical user registration form using the jQuery Validation plugin.


Register

<% form_for @user do |f| %> <%= f.error_messages %>

<%= f.label :email %>
<%= f.text_field :email %>

<%= f.label :password %>
<%= f.password_field :password %>

<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>

<%= f.submit "Register" %>

<% end %> <%= link_to "Cancel", :back %>

In HTML this form looks like this:





Notice that rails automatically added the id “new_user” for the form and provided ids for all elements of the form. This will come in handy a little later.

When this form is submitted the controller creates a new user model object, validates it using code in user.rb and saves the entry in the database. Relying on server-side validation done through the model is fine, but we can improve the usability of the application through client side validation.

Here are some of the things we want to check on the client side:

  1. All fields have been filled out
  2. The email is a valid email field.
  3. The password is at least 6 characters long
  4. The password and password_validation field match
  5. The email is not already in use

Loading up jQuery in the Application

Download the jQuery library .

Download the jQuery validation plugin.

Save the two plugins in public/javascripts/

Load up the plugins in your layout file. Ex: app/views/layouts/application.html.erb





My Nifty Rails Application
<%= stylesheet_link_tag 'application', 'thickbox' %>
<%= javascript_include_tag 'jquery-1.3.2.min', 'jquery.validate.min', 'application' %>

The order in which we add the three files matters. Application refers to the public/javascripts/application.js file. By rails convention we will put all the custom javascript for the application there.

To test that the files are loaded properly you can add the following code to application.js.


// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults

$(document).ready(function () {

alert("document ready");

});

Reload any page in your application and you should see the message pop up.

Writing the Validation

The jQuery validation plugin is really easy to set up. Once the DOM is loaded we will add validation requirements to each fields in the form using the validate() function. We reference the fields through their name attribute.


$(document).ready(function () {
$("#new_user").validate({
debug: true,
rules: {
"user[email]": {required: true, email: true},
"user[password]": {required: true, minlength: 6},
"user[password_confirmation]": {required: true, equalTo: "#user_password"}
}
});
});

The code is self explanatory. One thing that is specific to using jQuery validation with Rails forms, is that Rails adds field information to a hash map using form names like user[email]. Because of the square brackets we need to escape the form names used in the validate() function by surrounding them with quotes.

The debug:true option helps when writing validation rules because it makes sure that the form doesn’t get submitted even if there are syntax errors in the validation rules. Once you tested that the rules work, you can remove that option.

Here is the list of validation options available with the jQuery validation plugin.

Sprinkle some AJAX fairy dust with remote

Okay, so we’re checking that all the fields are filled out, etc., but the interesting part is checking whether or not the email address has already been used to create an account. To do this we will send an AJAX request to a rails action (let’s call it check_email) that will tell us if the given email address is already in use. Instead of responding with a regular html view, check_email responds with javascript code that is executed on the client side. To do this jQuery provides us with a special validation method called remote().

First let’s add the validation rule to the email field


// in application.js

$(document).ready(function () {
$("#new_user").validate({
debug: true,
rules: {
"user[email]": {required: true, email: true, remote:"/users/check_email" },  //added this
"user[password]": {required: true, minlength: 6},
"user[password_confirmation]": {required: true, equalTo: "#user_password"}
}
});
});

The remote function will send a GET request to

/users/check_email?user[email]=user@email.com

thus passing the email as a parameter to our action. The HTTP Accept parameter of the request is set to "text/javascript". This means the application is expecting a response in javascript format (actually the docs mention JSON) from the server. The action must use the email to determine if the email is already in use, and return true or false (no quotes).

Now let’s write the action and view and set it up in the routes.rb file.


# in users_controller.rb
def check_email
@user = User.find_by_email(params[:user][:email])

respond_to do |format|
format.json { render :json => !@user }
end
end

# in routes.rb

map.check_email "users/check_email", :controller => "users", :action => "check_email"
map.resources :users

If the user object exists for the given email, then the email is not available so the response is false and the validator will ask the user to change the email.

The remote function is a very powerful tool, because it allows us to combine server side and client side validation, thus providing better usability which makes our website visitors happy!

Resources

jQuery: http://www.jquery.com

jQuery Validation Plugin: http://plugins.jquery.com/project/validate

jQuery Validation Plugin Reference: http://docs.jquery.com/Plugins/Validation

This article has 50 comments

  1. Leonardo

    The definitely best tutorial about RoR and JQuery validations on the web.

    Keep up with the good job!

  2. Chris Homer

    Great tutorial.

    Have you thought about taking it one step further and write a helper or plugin that looks at the validations defined in the model and automatically generates the definition file for the jquery plugin?

  3. monica

    That’s a great idea! I guess the challenge there is to make the plugin flexible enough so it allows people to use all the other features that jQuery Validation offers (like specifying how the error messages are displayed, etc.).

    I’ll do some research to see if anyone already thought about this, and if they didn’t I will create a github project. Would you want to participate?

  4. Mike

    Firstly, I agree with the others – great tutorial!

    I initially couldn’t get the AJAX validation to work — not sure exactly why, but I found a solution that simplifies the whole AJAX process.

    Instead of rendering the “check_email.js.erb” file, simple change the check_email action to the following:

    def check_email
    @user = User.find_by_email(params[:user][:email])
    if @user
    @user = “false”
    else
    @user = “true”
    end

    respond_to do |format|
    format.json do
    render :json => @user
    end
    end
    end

    This bypasses the need for the separate js.erb file and sends the true/false declaration straight back to the validation script.

  5. Monica Olinescu

    Thanks Mike! That’s a great point.

    When calling render :json => “true” or render :json => “false” the response will be interpreted as a boolean (not a string). I updated the post.

  6. Betelgeuse

    Javascript validations have nothing to do with security as you can always hand craft HTTP requests any way you want them.

  7. Monica Olinescu

    @Elena, SM Glad it was useful. 🙂

    @Betelgeuse True, thanks for pointing that out. I updated the post. Javascript validation will not prevent people from submitting requests with malicious data and that’s why it’s very important to use server-side validation as well.

  8. Mike Trpcic

    There are better ways to go about this. The entire form should be abstracted into a partial, which is then rendered for both the new AND edit pages. This cuts down on code duplication. Then, assign a class to the form when doing your form_for. Now, apply your validations using the class as the selector instead of the ID (This must be done because the ID changes on the edit page to include the ID). Now you have one place to edit the form, working validations, and two complete views.

  9. Jimmy McGrath

    It’s worth pointing out that prototype and jQuery don’t always play nicely with each other as they both overload the $ symbol for their own purposes, so you can see errors like “$ is not a function”. There is some advice here about making jQuery work better with prototype (and other libraries).

    I have just wrestled with this problem for the past 1-2 hours, so I’ll share what I learnt.

    After following the advice from that link and others I was still having problems, like error messages “jQuery not defined”, then I removed the

    and instead included the files one at a time, making sure jQuery was included after prototype and before application.js

    And I was in business.

    Cheers.

  10. Jimmy McGrath

    whoops, my last has something escaped out.

    The code I deleted was:

    <%= javascript_include_tag :defaults %>

    which is a shorthand for including prototype.js, application.js and a number of other scripts.

  11. Jardel Bordignon

    def check_email
    @usuario = Usuario.find_by_email(params[:usuario][:email])
    respond_to do |format|
    format.json {render :json => !@usuario}
    end
    end

  12. Chris Whamond

    I’m just starting the transition to jQuery in my Rails apps and your tut is a great overview for these sweet validations. Nice to have validations on the front-end to avoid hitting the server. Thanks.

  13. Ecarrion

    Hi,

    I followed your tutorial and it’s great, but in the Ajax part it seems that ruby tries to render check_mail.erb not sending the respond to the script.

    Don’t know what i’m doing wrong, a little help will be appreciated.

    PD: Sorry for my bad English.

  14. Ecarrion

    Thanks for your quick response, I will check that link out.

    I have another question :), When the Ajax part return false, the plugin display a message “Please fix this Field”
    I have not been able to achieve to change this message for my own.

    Any Idea?

  15. Ecarrion

    Well, finally did it.

    Here is my code, in case of someone needs it

    By the way, Great Tutorial.

    $(document).ready(function () {
    $(“#new_user”).validate({
    debug: true,
    rules: {
    “user[name]”: {required: true, remote:”/users/check_name/”},
    “user[password]”: {required: true, minlength: 6}},
    messages: {
    “user[name]”: {
    remote: “That name is already taken”}
    }

    });
    });

  16. Roman

    thanx for the tuto, but in my app the ajax doesn’t works i don’t know why… if you have twitter i appreciate if you give me or just follow me @rome3ro, i have some questions.. thanx again 🙂

  17. Monica Olinescu

    Hi Roman. Sorry, I don’t use twitter, but you can post your question here and if I can I’d be glad to help + other people could benefit from it too.

  18. Roman

    that’s true… ok, i thing that a miss a javascript file or configure something for ajax functionality, because when i do a click in a submit button don’t do anything, not do the postback. When i use the code without remote parameter works fine only with client-side… in the night i work around that issue and maybe i can be more specific.
    Regards.

  19. Rafita

    Hallo,

    Nice tutorial ever 😀
    Anyway, anyone can help? rather than using $(“#new_user”).validate({….}), I wannna use $(“#edit_user”).validate({….}) but it seems like vallidation doesn’t work…. any idea?

  20. Elhu

    Really good tutorial!

    However, I’m stumbling upon some issues:
    Since my app is coded using RoR 3, I changed the
    respond_to do |format|
    format.json {render :json => !@user}
    end
    bit by something like
    respond_with !@user
    and added in my class the line:
    respond_to :html, :json

    To get a JSON response from the app, I use
    remote: “/users/new/check_email.json”.

    Now, when I visit the link in my browser, it works and I get the expected answer depending on whereas the email is already in use or not.

    The thing is, when I try it in my form, I don’t get a warning saying that the email is already in use.
    Furthermore, when the remote validation is activated and I type an invalid email address, even once I type a valid email, the validation error message is still displayed. (I don’t have this problem when I don’t set the remote validation.)

    Does anyone know how to fix this?

  21. Elhu

    OK, I just fixed my problem, so here is the solution, if it can help anyone:

    First: the latest version of the plugin isn’t apparently available on the JQuery page linked in the post, but you can find it at: http://bassistance.de/jquery-plugins/jquery-plugin-validation/
    Secondly: The plugin isn’t compatible with the latest version of JQuery. You have to rollback to 1.4.2 to get it to work.

    Works like a charm now, cheers!

  22. Pingback: links for 2011-03-03 | Digvijay and Ridhima's blog

  23. Jawad Rashid

    Thanks for the tutorial i was looking for using jquery validation remote method in rails and this article was exactly what i needed

  24. Abdul Basit

    Thanks for posting this! it really helped me especially when writing custom jquery rules, was stuck at that for sometime

  25. Vitaly

    If validation DOES NOT WORKING, try to change from
    $(“#new_user”).validate({
    — to —
    $(“form”).validate({

    – It should help.

  26. waqas

    Sleekd Hero you saved my day, thanks very much indeed for the simple & easy share, that’s what I just needed.

  27. kc00l

    @KP:
    #routes.rb
    resources :users do
    get :check_email, :in => :collection
    end

    To catch both #new_user and #edit_user forms I use a $(‘form[id*=user]’) selector… silly me wondering why the validate plugin wasn’t activated for the edit action form 😉

  28. babu

    I m really new to rails..can anyone help me learning by step by step programs or examples without scaffolding options…
    or just help me out with any of the sites to start out my learning

  29. jdk2588

    I tried using the tutorial but I am getting following errors when I use fire bug in firefox this is my code in application.js

    $(document).ready(function(){

    $(“#new_user”).validate({
    rules: {
    “user[name]”: “required”,
    “user[email]”: { required: true, email: true, remote:”/users/checkemail” }, //added this
    },
    messages:{
    “user[name]” : “Enter your name please”,
    “user[email]”:{
    required:”Enter your email address”,
    email:”Enter valid email address”
    },

    },
    });

    $(‘#new_user’).ajaxForm(function() {
    $(‘.modal-body’).html(‘Thank You! Close‘);

    });

    and in my routes.rb
    match ‘/users/checkemail’, :controller => ‘users’, :action => ‘checkemail’

    but firebug console says :
    ” [19:19:34.341] GET http://0.0.0.0:3000/users/checkemail?user%5Bemail%5D=djdd%40dd.com [HTTP/1.1 404 Not Found 29ms]”

    that means for the particular email when checked is not being validated .

    Any help would be great
    Thanks!

    });

  30. Jennifer

    Just wanted to let you know your post is still helping people. Thank you so much!! I was able to set this up in minutes thanks to you.

  31. Denys

    Hello!

    Thank you very much. You are great man)

    I can’t deal with remote function, that checks email. Thanks for helping so a lot of people)

  32. Rakesh

    This is the best post.
    I was searching for this from morning
    and i was not getting how to user name field in the javascript.
    This helped me really well.
    Thanks.

  33. cirovenpao.science

    I am using ruby2 and rails4. I have the validation using jquery. The validation errors are shown correctly, but when I click on submit button it does nothing though i had given the correct value for field. Can any body please help me to solve the problem? My codes are given below. Thank you.

  34. Pingback: JQuery Validate In Rails Applications | Tudip Technologies

Leave a Reply

Your email address will not be published. Required fields are marked *