FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
Architecture & Design
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
November 01, 2005
Product Review: Railing on AJAX

Rick Wayne
The Ruby on Rails Web application framework can jump-start 24-carat Web development, and the Asynchronous JavaScript And XML libraries sweeten the GUI pot.The catch: You'll have to code in Ruby.
November, 2005: Railing on AJAX

Software Development

November 2005

Railing on AJAX

The Ruby on Rails Web application framework can jump-start 24-carat Web development, and the Asynchronous JavaScript And XML libraries sweeten the GUI pot. The catch: You'll have to code in Ruby.

By Rick Wayne

Some of us are conservative. Cynical, even. But some are Gadget Boys and Girls, launching projects atop the latest, hottest tech. Some even rip working code asunder to hack in the sweet smell of the new. Initially a Gadget Boy, I was bludgeoned by promising-but-failed technology until cynicism grew on me like a fungus.

For me, Asynchronous JavaScript And XML (AJAX) and Ruby on Rails have proven effective fungicides. Friends, there is a genuinely new way to program Web apps. You can craft a gracile, adaptable GUI that runs in a browser but is as quick on its feet as a merengue dancer, then marry it to a robust model-view-controller (MVC) back-end framework that can produce a prototype database-driven Web app in less time than it takes to type these words.

But sporulating cynics take note: Jumping into AJAX and Rails does risk accepting the dreaded Early Adopter mantle (I used Rails 0.13 here). Plenty of production sites use Rails; Google's use of AJAX hardly needs mentioning. However, the APIs are still in flux, tools are only now hitting the market, and a handful of books were available at press time. And, of course, you'll have to learn Ruby, a language many still consider to be an upstart Python clone.

Have the lightweights and codgers fled? Excellent. I'll get started.

First, AJAX and Rails are by no means inseparable, but their synergy impels me to consider them as a partnership. AJAX, which obviates the Submit button in favor of live updates to pieces of a browser document, hooks quite nicely into the Rails application framework, whose clean separation of concerns and emphasis on convention over configuration (to say nothing of writing code) let you ramp up applications quickly and evade the Big Ball of Mud antipattern. I'll examine the application framework first, and then see how AJAX can make its GUIs sing.

Hello Rails
You'll need Ruby, both the language software and a bit of familiarity therewith. Space precludes a long introduction—see my article "A Joyful Gem" (Hello, World! Dec. 2002), crash around on www.ruby-lang.org, or check out Dave Thomas, Chad Fowler and Andy Hunt's excellent book Programming Ruby (2nd ed., Pragmatic Bookshelf, 2004). But here's the Ruby story in a nutshell: It handles off-the-cuff scripting as well as full-blown OO development. The syntax is spare but not unreadably terse. As with Smalltalk, everything's an object, so C's for (int ii=0; ii<4; ii++) becomes simply 1.upto 3. Like Lisp, Ruby lets you add or modify existing classes' methods. Ruby is statically untyped; instead, it uses Duck Typing. In other words, if you pass in a Toy to a method expecting a Duck, you'll get a runtime exception unless Toy responds to waddle() and quack(). It sounded like heresy and danger to a 10-year Java programmer like me. But soon I didn't miss the compiler a bit, and unit testing tends to catch what slips I made. Ruby emphasizes the principle of least surprise; you'll probably wind up just trying stuff instead of looking things up, because it usually works the way you expect. Finally, Yukihiro "Matz" Matsumoto designed Ruby to make programming fun again—and that's certainly been true for me.

For Windows, I recommend the One-Click Ruby Installer, which includes the RubyGems package manager (akin to Perl's CPAN). Ruby comes with Mac OS X and most Linux distributions. Or simply download the language from www.ruby-lang.org, and RubyGems from http://docs.rubygems.org. Then installing Rails is simple. From a command-line window, issue the command: gems install rails—include-dependencies. That and a database (see "System Requirements" in the Product Information box) will have you up and running. Rails' built-in Web server lets you prototype without mucking up your IIS or Apache installation.

Downloading and installing was so fast and straightforward that, as I wrote this, I just stuck it on whatever machine I happened to be working on—it wound up on our departmental Apache/Linux server, a Windows machine, another Linux box and my Mac.

Once installed, it's astoundingly easy to get a Web application running. A simple rails foo generates a subdirectory named foo, complete with the MVC controller, libraries and even the Web server. Change to foo and run ruby script/server, which starts the Web server, and you can point your browser at http://localhost:3000/ for the Rails welcome page.

Customizing your application means working in three kinds of files: Ruby source, HTML (optionally containing embedded Ruby à la PHP or JSP) and configuration files. There are precious few of the latter—Rails emphasizes convention over configuration, so processes like object-relational mapping happen for free. For instance, I had a table in my application's MySQL database called items; Rails automatically created a class called Item and populated it for me.

You'll probably recall that in the MVC architecture, model refers to the meat of an application, the data and the business logic that operates on it. The user sees views, which obtain and display model data. The controller takes in user data from the views, calls the model as necessary, and decides which view to present next. So in Rails, the canonical way to construct "Hello World" is to build a Say controller that can then present various views. Building the controller is simple (Look, Ma, no text editor!):

 [rick@ubadcat]$ script/generate controller Say
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/say
      exists  test/functional/
      create  app/controllers/say_controller.rb
      create  test/functional/say_controller_test.rb
      create  app/helpers/say_helper.rb

That's it? Yep. Our application will now respond to Say events. In fact, if you're running the built-in server in development mode, it'll respond to them right now; you needn't even bounce the server. How do we generate a Say event? Convention comes to the rescue again: A URL of /say/ invokes the Say controller. In particular, it calls that controller's default method; following time-honored Web tradition, that method is index. Opening the brand-new controller in a text editor shows a blank class definition, so we'll add an index method:

 class SayController < ApplicationController
  def index
     @someMessage = "Say What?" # Don't know what to say!
  end
 end

Finally, the controller needs a view to present to the user. Again, by convention, the index view for the Say controller is index.rhtml in app/views/say/. This is mostly HTML, with an embedded Ruby call to retrieve the message from the controller:

 <html>
  <head><title>Saying...</title></head>
  <body>
    <h1>What I'm sayin' is "<%= @message %>"</h1>
  </body>
 </html>

One more wrinkle: Instead of calling the index method, we can use the URL to specify any method we like. For example, by simply adding a hello method to the Say controller, we can specify that our app should respond to /say/hello/ with "Hello World!":

 class SayController < ApplicationController
  def index
     @someMessage = "Say What?"
  end

def hello @someMessage = "Hello World!" end end


Hello, World!
Here's the HTML template with its embedded Ruby call, the Say Controller with its hello method and the resulting HTML.

Supply a "hello" view, and you're done (see "Hello, World!"). As for the model, Rails can produce a straw-man "scaffold" create/read/update/delete (CRUD) application for a database table with a single call to the generate script. From there, you edit the generated Ruby class files to enforce your business rules. Simple validation—for example, to ensure that values have been supplied for required fields—can be a one-liner.

Getting Real
Obviously, there's a lot more to a real application than this. However, Rails is constructed so that you can start with the defaults for a first iteration, then elaborate, extend and specialize to your heart's content. For example, you'd hardly accept the default formatting for your Web pages. So Rails' layout feature lets you customize the overall look for a set of pages in one place, via clever use of HTML, plus embedded Ruby templates into which the dynamic content specific to a view gets injected.

As I elaborated on my own application—no toy, this: It's an instructional-support tool for a university class—I came to appreciate the Rails philosophy of ruthlessly eliminating repetition (a.k.a. DRY, for "Don't Repeat Yourself"). Except for the fairly explicit contracts between components, changes made in one place tend not to have the ripple effect that makes working with some frameworks so frustrating.

I was sold on test-driven development long ago, but have always found my Web applications to be tough testing customers. Unless you're fairly disciplined about your architecture, or use a framework, it's easy to fling some embedded code into some HTML and wind up with something that can be tested only by a human running a browser. Rails' MVC design, like that of Java Server Faces or Apache Struts, helps keep your code divisible into testable pieces. Rails goes further, though, building a unit-testing framework into your application from the very start. It's easy to set up tests for your models and controllers, especially given Rails' built-in support for canned test datasets (that are automatically emptied between unit tests) and its clever use of an introspection-like technique that streamlines many asserts into one-liners.

Hello AJAX
If you're unfamiliar with AJAX, here's the story in 39 words: Browsers whose JavaScript interpreters provide the XMLHttpRequest object can make nonblocking calls back to the server. The server can return pieces of HTML to be displayed, JavaScript to be run by the browser, or indeed any data you like. The key is that since JavaScript has access to the document object model (DOM), it can replace any piece of it. This gives the developer fine-grained control over the user experience; no need to pile all interaction between server and browser into one great submit and refresh cycle. Any event that JavaScript can detect can trigger an update.

It's perfectly possible to code the whole works yourself in JavaScript—if you're insane. Better to leverage the existing JavaScript libraries, which insulate you from the gory details. Better still, do it from within Rails, which not only provides you with several useful libraries, but wraps them in the framework so that you hardly need lift a finger to use AJAX.

Let's build a toy application that echoes the HTTP request REMOTE_ADDR variable, as well as the HTTP_HOST variable. We'll start with a traditional, click-link-to-replace page app, so we'll need a WhoAreWe controller:

 class WhoAreWeController < ApplicationController
   def index
   end

def saywho raddr = request.env['REMOTE_ADDR'] hhost = request.env['HTTP_HOST'] render_text "You are #{raddr} and I am #{hhost}" end end

We'll also need a view. Note the link_to Ruby method embedded therein, which constructs the appropriate HTML hyperlink that activates the saywho method in the previous controller:

 <html>
   <head>
     <title>Who's Having This Conversation?</title>
   </head>
   <body>
     <h2>Who are we, anyway?</h2>
     <div id="answer_div">
       For the answer to this deep philosophical question...
       <%= link_to( "click here",
                    :action => :saywho ) %>
     </div>

</body> </html>

So far, nothing earth-shattering; the browser shows a new page giving the local and remote addresses when you click the link. Watch my hands, ladies and gentlemen, as I prestidigitate AJAX into this application! First, we'll need to include the Prototype library in our view; that's the javascript_include_tag line just after <title>. Then, by switching link_to for link_to_remote, we're suddenly swizzling our DOM in place.

 <html>
   <head>
     <title>Who's Having This Conversation?</title>
     <%= javascript_include_tag "prototype" %>
   </head>
   <body>
     <h2>Who are we, anyway?</h2>
     <div id="answer_div">
       For the answer to this deep philosophical question...
       <%= link_to_remote( "click here",
                          :update => "answer_div",
                          :url =>{ :action => :saywho }) %>
     </div>

</body> </html>

Granted, this little example could just as easily be done with a page refresh. But as page complexity grows, the traffic and time to generate go up. Bear in mind, too, that AJAX gives you even more flexibility. Every click, hover or keystroke is grist for the JavaScript event loop, so that you can build lists that autofill as user types, or cache database lookups as the user hovers over a map. AJAX and Rails support more sophisticated modes of interaction, too; you can define callbacks, generate live progress feedback, or add a bevy of special effects, including scaling, fading or elements that vanish in little puffs of smoke.

Should You Rail on AJAX?
Overall, as you've doubtless discerned, I'm quite taken with Rails. Its adherence to the principles of DRY and the separation of concerns encourages experimentation and speeds up iterations, while the supplied class library offers what's needful to build Web apps. The emphasis on test-driven development convinces me that this is a professional tool designed to build robust software. While it's laughably easy to get a toy app running, expect to spend a few days learning the framework before you can crank out production code (see "Tools, References and Resources"). Deployment is also a bit of a concern. The consensus I read from the user community is that running an interpreted language via standard CGI calls on Apache or Internet Information Server won't scale too far; you'll wind up trying to configure the FastCGI module or using an alternative server like lighttpd. I often found myself waiting several seconds for our modest 1GHz/1GB Athlon server to show a new Rails page. It was a no-brainer to get my application up and running on Apache using a VirtualHost directive, but I found it more problematic to get working in the "default" server.

AJAX, by itself or combined with Rails, is an even easier call. It takes no great prescience to predict that page-at-a-time, fill-out-and-submit Web apps are going to be looking mighty stodgy in a year. The only reason not to start adopting AJAX today is if you can't get it to meld seamlessly with your current application framework. But put it together with Rails, and you're hummin'.

Tools, References and Resources

Curt Hibbs' must-read articles on O'Reilly's OnLAMP site. My toy AJAX example is derived from one of Hibbs'.

Agile Web Development with Rails by Dave Thomas, David Heinemeier Hansson et al. (Pragmatic Bookshelf, 2005) is the definitive text on Rails, with a chapter on AJAX.

The TextMate text editor (a Mac OS X tool) is useful for editing sets of files in a hierarchy, which you do a lot with Rails.

Another nice new Mac OS X tool for Rails is Locomotive, which nicely wraps the housekeeping of generating applications, running the server and such in a GUI.

What AJAX tools are available? Bindows has support for Web services; Ajax.NET, a free library for hooking Ajax Web apps to .NET back ends; and Echo2, a free library that does the same for Java.

On the horizon: At press time, Microsoft, Sun, Tibco, ClearNova and Macromedia had all announced or beta-released AJAX tools.

As for support, the Rails site lists a few dozen consultants; the mailing list generates about 50-100 messages per day. My questions there were answered within hours.

—RW


Ruby on Rails 0.13 and AJAX

www.rubyonrails.org

Technical Requirements: Ruby runs on darn near anything; you'll need at least a CGI-capable Web server for production, though Fast-CGI would be better. Rails connects easily to MySQL, PostgreSQL, SQLite, Oracle, SQLServer and DB2 out of the box.

Pros:
  1. Robust, test-driven Web apps are simple to start.
  2. Built-in AJAX support simplifies next-gen browser-based development.
  3. Separation of concerns helps keep code maintainable over time—and it's in Ruby.

Cons:

  1. Ruby programmers are still rare.
  2. While Web services are supported, management and integration tools have not yet reached the level of Java or .NET; integrating Rails apps into an SOA will involve some hand-coding.
  3. Scaling your app to handle real-world loads may involve some tricky server tweaking.www.rubyonrails.org


New & Noteworthy Editor Rick Wayne has way too much fun with Web-enabled ecosystem management software at the University of Wisconsin. E-mail him at fewayne@facstaff.wisc.edu.

TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK