This post originated from an RSS feed registered with Ruby Buzz
by Matthias Georgi.
Original Post: Fast Auto-completion with Rails, Scriptaculous and JSON
Feed Title: Matthias Georgi
Feed URL: http://feeds.feedburner.com/matthias-georgi?format=xml
Feed Description: Webdev, Gamedev and Interaction Design.
Inspired by the excellent Rails Recipes book , I created an improved Auto-completion helper, which uses JSON and AJAX instead of a script tag for loading the completions.
What we want to achieve is a search field, which pops up immediately, showing us a list of possible completions for our search word. Look at Google Suggest to get an idea.
Rails already has an auto_complete_field, which sends an AJAX request for each keystroke. This approach is quite slow, but works in most cases, especially for large datasets auto_complete_field is the better choice.
Our idea, stolen from the Rails Recipes book is to fetch the array of possible completions only once. Each keystroke will trigger only a local lookup and need no further server interaction. Scriptaculous already has the right tool for this job: Autocompleter.Local . We will just pass a javascript array of possible completions to the constructor and we're done.
OK, let's start. First we need the CSS used by Autocompleter.Local, which styles the choices box:
Rails already has an controller macro for generating a auto completion action. We will create a similar macro, which will generate an action, which in turn generates the JSON response. Sounds complex, but the implementation is quite easy:
def self.fast_auto_complete_for(object, method, options ={}) define_method("auto_complete_for_#{object}_#{method}")do render :json => object.to_s.camelize.constantize.find(:all).map(&method).to_json end end
The response of the generated action will now contain a list of all values for the desired attribute. You can use it like:
fast_auto_complete_for :sport, :name
Now let us get into the tricky part: the javascript macro helper. How will we get the completion list? Prototype includes the Ajax.Request class, which sends an Ajax Request to our generated action and fetches the array encoded as JSON. Furthermore we have to generate a div which will hold the popup list for our completion entries. Without going into detail, I'll just show you the code:
Note, that I use my simple markaby helper, which I presented in my last post. It is just a little more convenient not to do all this string concatenation. Our helper needs the id for the text field we want to enhance. Based on this id the helper generates the div for presenting the completion entries. It is also required to pass the url of the json action, which is in our case /sports/auto_complete_for_sport_name.
Well, that's it. Now you may enjoy snappy auto-completion and feel good about using bleeding edge technology like AJAX and JSON.
By the way, I'm really having a hard time formatting my code snippets here. I use this syntax-highlighter , which just works, as the styles are directly encoded into the span tags. Unfortunately every edit opertion at blogger.com swallows some whitespaces, which is quite annoying. Maybe somebody knows a better way to do this?