Making jQuery and Rails play nice with AJAX.

Sometimes you need to observe for a client-side event (click, drag-n-drop, column resize, etc.) and store the result in your database. For example, say your application has customizable profile pages where users can rearrange, add, remove, and resize widgets (e.g. stock ticker, twitter feed, etc.).

Now, jQuery makes this functionality super easy – just a few lines of code. But here’s the tricky part: the configuration of each profile page needs to be stored in your database and be associated with a given user. Otherwise users would lose all their changes on page refresh. No good.

This means every time a user changes something (e.g. removes a stock ticker) you need to let rails know the profile has been changed so that the appropriate columns can be updated in your database (e.g. set the ticker’s ‘hidden’ boolean to true). And ideally, this should all happen silently in the background so that the user’s not even aware their changes are being saved on the fly.

Now, we’re talking about making the client talk to the server without a page refresh. That means AJAX. So here’s the plan…

1. Create your javascript event.

For simplicity, say you’d like to let the user can change the background color of their profile page. Let’s give them three buttons to toggle between red, yellow, and purple. Your html would look like this:

<body>
Make Green
Make Yellow
Make Purple
</body>

And your jQuery would look like this:

$('.change_bg_color').click(function() {
	if (this.id == 'green') { $('body').css('background-color', 'green') };
	if (this.id == 'yellow') { $('body').css('background-color', 'yellow') };
	if (this.id == 'purple') { $('body').css('background-color', 'purple') };
});

That will get our background changing color, but as soon as the page refreshes we’ll lose our changes. So let’s get rails involved.

2. Set up the appropriate models and associations

I’ll move pretty quickly here cause it’s so easy. I assume you have a current_user stored in your session. I’ll also assume you’ve set up a one-to-one association between ‘users’ and ‘profile_settings.’ This means you should be able to do something like this in your controller:

def make_background_green
	current_user.profile_setting.update_attributes(:background_color => 'green')
end

And then you can apply this color using inline style:

<body style="background-color=<%= current_user.profile_setting.background_color %>;" >
<%= link_to "Make Green", :action => "make_background_green" %>
<%= link_to "Make Yellow", :action => "make_background_yellow" %>
<%= link_to "Make Purple", :action => "make_background_purple" %>
</body>

Of course this is just nasty for a couple of reasons: (a) you’d have to write a new method for each possible color, (b) the markup is sort of ugly, and (c) we’re relying on a page refresh to do the work. So let’s clean this up a bit using AJAX.

3. Update your profile settings via AJAX.

First, let’s get our html looking better:

<body style="background-color=<%= current_user.profile_setting.background_color %>;" >
Make Green
Make Yellow
Make Purple
</body>

Then lets add some AJAX to our click event:

$('h3').click(function() {
	if (this.id == 'green') { $('body').css('background-color', 'green') };
	if (this.id == 'yellow') { $('body').css('background-color', 'yellow') };
	if (this.id == 'purple') { $('body').css('background-color', 'purple') };		

	$.post('http://your_site.com/profile_controller/change_background_color', {
		'background_color' : this.id
	});
});

Here’s where you need to pay attention. We’re sending an AJAX post request with two arguments: (1) the url we’d like to load and (2) the data we’d like to pass along as a key/value pair. This means your controller is going to fire the ‘change_background_color’ action and will have access to the params[:background_color] with a value equal to the clicked element’s id.

And so your controller will look like this:

def change_background_color
  current_user.profile_setting.update_attributes(:background_color => params[:background_color])
  render :nothing => true  # make sure the action knows not to load a template
end

4. Mission accomplished.

Your profile settings should now be updating quietly in the background. If you have any problems, start up firebug and watch your AJAX hit register in the console log. This can be very helpful when debugging. But don’t get discouraged. Once you get this process down, all sorts of cool things become possible.

Tags: , , ,

Your thoughts?

Preview