Archive for the ‘Ruby on Rails’ Category

The REAL Rails AJAX Select Control Tutorial

April 1, 2006 in Javascript,Programming,Ruby,Ruby on Rails | Comments (0)

I’ve been trying for a while to implement functionality in Rails where, when the value of one selector is changed by the user, a related selector is refilled with associated data. I’m rewriting one of my PHP applications (The CIty of Villains Registry) in Rails, so I’ve already implemented similar functionality in PHP. Unfortunately, the amount of documentation out there for this sort of thing is rather sparse, and leaves a couple of wide holes open for developers to fall into. I finally got it to work, but it was tough pulling all of the information together. I figured it would be worth my while to post what I did to help others wrestling with the same thing (and there appear to be quite a few).

Create a Partial Template to Render your Select Control

For my application, there is one select control for choosing a hero archetype. Two other selectors let you choose primary and secondary powersets. We’ll just concentrate on the primary powerset selector for this exercise. When the page loads, whatever value is in the archetype selector will determine what values should be available in the powerset selector, so my template does a quick find based on whatever archetype ID is buried in the hero model and generates a select control with the matching powerset names and ID’s.

<%=select(“hero”, “primary_powerset_id”, ArchetypePrimary.find_all_by_archetype_id(archetype_id).collect {|p| [, p.powerset_id ] })%>

For my application, this got saved as app/views/hero/_primary_powerset_selector.rhtml

Modify your Page Template to render your Select Control

Now that we have a partial template, we need to get it to render in the parent page. Keep in mind, though, that with an AJAX call, we’re going to be replacing the content of an object on the page with the rendered output, so we’re going to bury the render inside a span tag. We’ll use that name of that tag later on when we make our AJAX call.

<span id=’primary_powerset_selector’>
<%= render :partial => ‘primary_powerset_selector’, :locals => {:archetype_id => @hero.archetype_id}%>

In my application, this code goes in the app/view/hero/_form.rhtml file where I want the select control to appear.

Create an Action to Render your Partial Template

What we’ve done so far will make the filtered selector appear on the page, loaded with the filtered set of results. In order to make it dynamic, we have to build a custom action into our controller that knows how to refresh the select control. It will take the new archetype ID as an argument, then render our template to produce a select control. It’s a pretty simple call, it just takes the passed argument and renders the partial:

def fill_primary_powerset_box
render(:partial => ‘primary_powerset_selector’, :locals => {:archetype_id => @params[:archetype_id]})

In my application, this method was added to the app/controllers/hero_controller.rb file.

Add the AJAX Call to your Page Template

Everything is in place, so now we can ask Rails to render the AJAX call that will dynamically render the select control into our span. Somewhere after the span, drop something like this into your template:

<%= observe_field(
:update => :primary_powerset_selector,
:url => {:controller => ‘hero’, :action => :fill_primary_powerset_box},
:with => “‘archetype_id=’ + value”)

So what’s worth noticing is the following: I’m passing in the name of the selector that is being watched (when my hero_archetype_selector changes I want this event to be fired), I’m giving it the name of the span I want to be updated with the new content (primary_power_selector is the name of my span), I’m telling it to user the hero controller and call the fill_primary_powerset_box action, and I’m handing the value of the control that changed as an argument named archetype_id.

If you’ve been trying to figure this stuff out for any time at all you’re going to notice one that is missing: The frequency parameter. Every example I have seen for observe_field passes in a frequency parameter, but you only need to use this if you really need to be polling, like maybe you’re pulling in search result as the user types, or dynamically rendering the text being typed somewhere else on the page. You don’t need it to link two select controls together. Leaving this parameter out makes the event fire when the value in the selector changes. I had started out using a frequency of zero, which would make the event fire when it should, but the Prototype library would throw an error. This is because it was sending my zero as the callback instead of a function reference. Just leave it out and you’ll be fine.

It was a lot of working figuring out how to set this up right for the incredibly small amount of code it actually takes to pull it off. Hopefully this will make it easier for you set up a similar configuration in your own applications.


Now that I have it working I do notice that the callback is considerably slower than my homebrew PHP version was. Maybe it’s because I’m on a shared server, and maybe it’s because I’m running in dev mode right now. I have to poke around at it a little bit more.

Helpful resources:

  • Rails Hosting – This site has some good examples of using the Prototype library for AJAX and client side scripting with Ruby.
  • Using Prototype v1.4.0 – This helped me ultimately deduce the problem in my rendered calls since it describes the actual constructors and arguments to the Prototype objects. I could see where Form.Element.EventObserver did not take a frequency argument, and that my frequency value of zero was being passed in place of the callback.
  • Rory Hanson’s – This was where I started, since it came up first in Google. It gives some good examples of how to set up the code. You’ll notice, however, the number of people having difficulty making it work.
  • Adam C. Hegedus’s Blog Entry – This one really helped me get started, picking up where Rory’s blog left off.