MetaGreg

writes code that writes code for food

How to share code between Javascript and Rails

with 2 comments

Rails’ validations is great because it allows you to quickly implement the valid states of your models and at the same time have a ready-made way of displaying the errors to your users. For example, below is a screenshot of a registration form written with just a few lines of code:

However, this approach requires the server to perform the validation even for simple things like checking the length of a password. To improve response time (and thus the user experience), we use Javascript to pass some workload to the browser. For example, the popular jQuery framework has a validation plugin similar to that of Rails.

Here are the Rails and jQuery code snippets for our form validation:

validates_presence_of     :login
validates_length_of       :login,    :within => 3..40
$('#new_user').validate({
rules: {
'user[login]': {
required: true,
maxlength: 40,
minlength: 3
}
},
});

Notice the length condition of the login is repeated in Rails and jQuery, which violates the Don’t Repeat Yourself principle. To remedy this, one approach is to publish the constants from your Rails code as Javascript code. To do this, we need to refactor our model a bit and use a Rails helper method.

# User model
MIN_LENGTH = 3
MAX_LENGTH = 40

validates_presence_of     :login
validates_length_of       :login,    :within => MIN_LENGTH..MAX_LENGTH

# in your helper
def js_user_format
format = {
"MAX_LENGTH" => User::MAX_LENGTH,
"MIN_LENGTH" => User::MIN_LENGTH
}
javascript_tag "var User=#{format.to_json}"
end

Then, in your form template:

<%= js_user_format %>

This will produce the following Javascript code in your page:

<script type="text/javascript">
//<![CDATA[
var User={"MIN_LENGTH": 3, "MAX_LENGTH": 40}
//]]>
</script>

You can now improve your jQuery code:

$('#new_user').validate({
rules: {
'user[login]': {
required: true,
maxlength: User.MAX_LENGTH,
minlength: User.MIN_LENGTH
}
},
});

This is just a simple example and I bet you can extend this one. For example, if you use regular expressions with validates_format_of, you can use the same regex to validate the format of the input in jQuery.

Update: One reader had a problem including Javascript in templates using HAML. You can include Javascript in HAML templates but there should be no indentation. Otherwise, HAML would complain of “illegal nesting”. Of course, no indentation would make it harder to read your Javascript. To preserve the whitespace, you can use multiline string. I also suggest you put it in a helper to isolate your Javascript code. If you can get away with it in your helper, the better.

# in helper
def js_foo
javascript_tag <<-eos
function onAfter() {
var current = $(this).attr('id');
if (current!="") {
$('.'+current).removeClass("active", 'timeout');
}
};
eos
end

# in haml template
= js_foo
Share and Enjoy:
  • Digg
  • Facebook
  • StumbleUpon
  • TwitThis

Related posts:

Written by Greg Moreno

July 24th, 2009 at 10:17 am

Posted in Geekiness

Tagged with ,

2 Responses to 'How to share code between Javascript and Rails'

Subscribe to comments with RSS or TrackBack to 'How to share code between Javascript and Rails'.

  1. Thanks Greg..
    I moved most of javascript on erb to helpers based on your code a few days ago.

    Here’s a better way of handling javascript and haml (for those using it).
    On head tag of layout, add:

    =yield :head

    then on helper:

    def mail_gallery_js
    content_for(:head) {
    javascript_tag <<-eos
    $(document).ready(function($) {
    all_js_code_here
    });
    eos
    }

    Katz

    29 Jul 09 at 7:54 am

  2. I prefer using just a helper so I could the js code anywhere in the page. For example, I put the jQuery validation after a form.

    Greg Moreno

    29 Jul 09 at 10:29 am

Leave a Reply