Creating a Live Datagrid

:: Development
March 4, 2006 - over 4 years ago
Platform: Ruby on Rails 1.0, mySQL 4.x/5.0
Tested Browsers: Firefox 1.5, IE 6.0, Safari 1.3
Tag As: AJAX, data grid, partials, validation
Editor: Stephanie Lyons
Source Code: here - version 1.00
Demo Page: Unspace Live Datagrid
Historically, data sub-forms are not something that have been presented well on the web. Pop-up windows and browser page refreshing are a significant regression from the interfaces which have been provided by client/server desktop applications for over a decade. Luckily, with the advent of Rails and its partials rendering, we are in a position to do something about this usability shortfall.
Grab a copy of the source code and follow along! In our example, we are going to create a small but entirely practical application that allows you to list the people in your family, their relationship to you, their birthday, and well... whether they're dead. Hey - it happens to most of us sooner or later.1
First, we need to create the required tables in mySQL. I have supplied the required sql creation scripts in the /db directory so that you do not have to create table definitions. We will look at two tables; familymembers and sessionlists. Sessionlists are required in our example to keep track of each unique visitor to the site, so that we can generate sample data for new eyes. Creating the schemas is beyond the scope of this article; you can likely run the CREATE TABLE statements inside your query browser.
Once you have your database set up, generate models (Familymember and Sessionlist) and how about a controller, too (datagrid) while you're at it. The only complexity here is that with the Familymember model, we will use a facade column to handle translation of the birthday field to and from the shortdate format we use on the site. Just remember to use :birthday_sd instead of :birthday in our controller and views.
Other configuration includes merging the CSS and javascript found in /public with your project. You will have to add some entries to your routes.rb, but we'll come back to that.
Partials are snippets of XHTML code which can be rendered to the browser, without requiring a page refresh. The Prototype javascript library accomplishes this magic by using an asyncronous HTTP connection. We can fetch a block of pre-rendered markup, and add it to the page by setting the innerHTML attribute of a pre-determined block element - usually a SPAN or DIV.
On its own, this would be extremely useful; however, the true power of partials is realized when you see that you can pass a collection object into a partial. Rails will spit out the markup once for each item in the collection. The only thing the visitor will see is a DIV - in our case, with an id of "familymembers", which is set to receive all of the updated markup after each change.
If you look at the datagrid controller, most of the functions are divided up into:
- displaying the container page and populating it with data for new visitors (index)
- rendering (as well as adding and removing) records
- updating the fields in the database based on user action
In our example, we are using the unique session.session_id value to present a separate list of data to each visitor to the site.
In fact, if you look at the index function, we are actually generating a list of fake people for each new browser that comes to
the site!
Most of the tricky work is a combination of Rails partials, clever routing, and some [fancy|ugly] javascript validation coding. This custom javascript, datagrid.js, uses the Request functionality of the Prototype library to pass the update requests along to the server. We have to test whether the visitor is using IE or not, as we make use of DOM scripting; IE does not consider the whitespace between DOM nodes important enough to count it.
This causes problems when we attempt to access the database id of the current row using a relative DOM path! At any rate, be prepared to change the 4 and 9 constants to reflect the number of fields in your datagrid, keeping in mind that IE doesn't count whitespace - hence the 4 in this scenario. If you had 5 fields, you'd change this to 5 and 11, respectively.
The id is actually stored in a hidden field in the last cell with the delete button of each row - sneaky, it's true. Our project does two further checks: it makes sure that you enter a valid date, and it has special handling for check boxes. One of the great advantages to this approach is that allows maximum flexibility for how your grid will work.
You need to understand the modifications to the routes.rb file before we call this a completed exercise. The first route accepts an additional parameter - :data - which we'll use to pass in the data that the item in question is being changed to. It defaults to nil, which we handle as a special case. The second route is more complex, especially if you've never seen regular expressions before. Regular expressions (regex) are a powerful tool that can be used to match very sophistcated patterns in text strings, URLS, and many other things. In this case, they are there to guarantee that the dates being passed are valid.
If you've made it this far, you probably realize that there is not much to this, once you've got the basic steps covered. In fact, the number of characters in this article (6040) is higher than the characters in the source code (4287) required to get this running! Of course, we tried our best to make everything as straight-forward as possible; adhering to DRY principles and using intelligent variable names for everything. However, it's more than that - Rails simply makes short work of this sort of task, if you know the tools you now have at your disposal. By making use of the javascript "this" pointer, we can make each line of the table - rendered using partials DIVs, of course! - self-aware -enough to manage itself without any kind of external overhead. This is undeniably sexy!
Now go play around with it and tell us what you think! We are sure you are going to suggest improvements, so drop us a line
anytime with some constructive feedback.
1 We recognize that many of you will in fact live forever, in the form of your prepaid World of Warcraft avatars. We nod politely and wish you the best of times with that.