`
Gene
  • 浏览: 50382 次
社区版块
存档分类
最新评论

Crossing borders: Ajax on Rails

阅读更多

Crossing borders: Ajax on Rails

Why Ajax works so well with Ruby

developerWorks
Document options
<noscript></noscript><noscript><tr valign="top"><td width="8"><img alt="" height="1" width="8" src="//www.ibm.com/i/c.gif"/></td><td width="16"><img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif"/></td><td class="small" width="122"><p><span class="ast">Document options requiring JavaScript are not displayed</span></p></td></tr></noscript> <script type="text/javascript" language="JavaScript"> </script> <script type="text/javascript" language="JavaScript"> </script> <!----><!---->
Set printer orientation to landscape mode

Print this page

Email this page

E-mail this page

<!----><!----> <!----><!---->
Rate this page

Help us improve this content


Level: Intermediate

Bruce Tate (bruce.tate@j2life.com), President, RapidRed

05 Dec 2006

The hype for Ajax, a technique for making Web pages more interactive, is in overdrive. The Ruby on Rails framework is also flourishing, partly on the strength of its excellent Ajax integration. Find out what makes Ajax on Rails such a powerful combination.
<!----> <script type="text/javascript" language="JavaScript"> <!----> </script> <!---->

The previous two Crossing borders articles (see Resources) walked you through Streamlined, a Rails add-on that makes effective use of scaffolding to generate simple, Ajax-enabled user interfaces quickly. Unless you've been hiding under a rock, you recognize Ajax as a programming technique that uses XML, JavaScript, and Web standards to create highly interactive Web pages, such as those you'll find at Google Maps and hundreds of other sites. Several readers of the Streamlined articles asked me to describe the way Ajax works on Ruby on Rails. This article walks through a couple of simple Ajax examples and, along the way, shows you what makes the Ruby/Ajax combination so successful. In the next article in this series, I'll dig into JavaScript as a programming language.

Ajax defined

Ajax stands for Asynchronous JavaScript + XML. Jesse James Garrett, an information architect, came up with the term in 2005 to describe a technique that had seen niche use for nearly a decade (see Resources). Ajax use then exploded, with a simultaneous growth in libraries, popular Web sites, and literature.

Ajax redefines the basic browser's usage model, which was to render a page at a time. Ajax lets the browser communicate with the server between page updates. The upside is a richer user experience, at the cost of complexity. Ajax works by sending XML between the client and server using JavaScript client-side libraries. Ajax developers can send asynchronous requests from the client at any time, so user interactions can continue while the server processes the requests. This is the flow of an Ajax request:

About this series

In the Crossing borders series, author Bruce Tate advances the notion that today's Java programmers are well served by learning other approaches and languages. The programming landscape has changed since Java technology was the obvious best choice for all development projects. Other frameworks are shaping the way Java frameworks are built, and the concepts you learn from other languages can inform your Java programming. The Python (or Ruby, or Smalltalk, or ... fill in the blank) code you write can change the way that you approach Java coding.

This series introduces you to programming concepts and techniques that are radically different from, but also directly applicable to, Java development. In some cases, you'll need to integrate the technology to take advantage of it. In others, you'll be able to apply the concepts directly. The individual tool isn't as important as the idea that other languages and frameworks can influence developers, frameworks, and even fundamental approaches in the Java community.

  1. An event, such as a user mouse click or a programming timer trigger, initiates a JavaScript function.

  2. The JavaScript function creates a request for a partial page rather than a full page. JavaScript then sends that request to the Web server via HTTP.

  3. This HTTP request invokes a script on the server, such as a Rails controller method or a Java™ servlet.

  4. The server script creates an XML document and returns it to the client.

  5. Upon receiving the result, the client asynchronously creates, updates, or deletes part of the Web page, such as a list element, div tag, or image.

All Ajax applications use an approach that looks something like this sequence. For example, consider an application that lets you maintain dictionary words with their definitions. Old-style applications would force a new page view for you to edit a definition. Ajax would allow in-place editing, by replacing definition text with an entry field, and then replacing that form with the updated definition.

The components of an Ajax solution are:

  • A client-side JavaScript library to manage the asynchronous request.
  • A server-side library for dealing with the incoming request and formulating an XML response.
  • A client-side library to deal with the resulting XML.
  • A library -- called the document object model (DOM) -- allowing updates of the existing Web page.
  • Helper routines to deal with inevitable UI and integration issues.

This event/request/response/replace model is the core model for most Ajax applications, but if you're new to Ajax, you'd be surprised at the number of available libraries and the broad differences among them. Many Ajax frameworks dot the industry landscape, with frequent overlap and no sure winners. In the Java marketplace alone, dozens of libraries are in use, including Echo, Dojo, DWR, the Google Web Toolkit (GWT), Java Web Parts, AjaxAnywhere, AjaxTags, Scriptaculous, and Prototype. These frameworks use dramatically different approaches. Some, such as GWT, seek to hide any JavaScript by providing Java libraries that generate JavaScript code. Others aim to make JavaScript easier to use. Some are wildly comprehensive, such as Dom4J, and others simply strive to solve one small problem well. As with many popular new technologies, this checkerboard landscape of solutions will be difficult to navigate for quite some time, and the debugging tools, UI practices (such as the Back button), and wise development practices will materialize slowly. The strength of Ajax libraries on the Java platform is their diversity. That's also the weakness, because that diversity breeds indecision, integration concerns, and complexity.

With Ruby on Rails, the experience is dramatically different for two reasons. First, Ruby on Rails has one core Web development platform: Ruby on Rails. Second, most of the Ajax development experience on Rails so far has centered around two core frameworks: Scriptaculous and Prototype (see Resources). The Rails approach, using run-time code generation and custom tags, insulates you from the complexities of JavaScript. It's time to see for yourself. As always, if you want to code along, you need to download Rails, which comes with the necessary Ajax frameworks (see Resources). Crack open your Rails environment, and take a look with me.



Back to top


A simple Rails application without Ajax

To use Rails and Ajax, you'll create an empty project and generate a controller with two methods. One controls a simple page, and another sets up an Ajax response. Type the following commands:

rails ajax
cd ajax
script/generate controller ajax show time

The first and second lines generate a Rails project and switch to the new directory. The third generates a controller called ajax and views for two actions: show and time. Listing 1 shows the controller code:


Listing 1. A controller with two empty methods
class AjaxController < ApplicationController

def show
end

def time
end
end

You'll first build two simple views without Ajax and then tie them together with Ajax. Edit the show.rhtml view in app/views/ajax and make it look like Listing 2:


Listing 2. A simple view
<h1>Ajax show</h1>
Click this link to show the current <%= link_to "time", :action => "time" %>.

The code in Listings 1 and 2 includes no Ajax support, but I'll dissect it anyway. First, look at the controller in Listing 1. Two empty controller methods process incoming HTTP requests. If you don't explicitly render a view (using a render method), Rails renders the view with the same name as the method. Because the Scriptaculous and Prototype libraries also use HTTP, Rails doesn't need to make any distinction between standard HTTP methods and Ajax methods.

Now turn your attention to the view in Listing 2. Most of the code is simple HTML, with the exception of the link_to helper in the second line: <%= link_to "time", :action => "time" %>.

As you've seen in previous Crossing borders articles, Ruby replaces the code between <%=h and %> with the value of the expression. In this case, the link-to method is a helper that generates a simple HTML link. You can see the link by executing the code. Start the server by typing script/server and then point your browser to http://localhost:3000/ajax/show. You'll see the view shown in Figure 1:


Figure 1. A simple user interface without Ajax
Simple user interface without Ajax

In your browser, click the menu options to view the page source (View > Source in Internet Explorer and View > Page Source in Firefox). You'll see the code in Listing 3:


Listing 3. The view generated by show.rhtml
<h1>Ajax show</h1>
Click this link to show the current <a href="/ajax/time">time</a>.

Notice the link code in Listing 3. The template shields the Rails user from the tedious and error-prone HTML syntax. (The Ajax code works in the same way: you use helper methods to drop in JavaScript code that manages the remote requests and HTML replacement for you.) If you click the link, you'll see the default view for the time method, but I haven't implemented it yet. To remedy that, replace the time method in app/controllers/ajax_controller.rb with the code in Listing 4. Keeping things simple, I'm rendering the view directly from the controller. Later, I'll clean things up and render a view.


Listing 4. Rendering the time
def time
render_text "The current time is #{Time.now.to_s}"
end

Now, when you click the link, you get the view in Figure 2:


Figure 2. A view with no Ajax
Simple view with no Ajax

You can immediately see a problem with this UI. The two views don't belong on separate pages. The application represents a single concept: click a link to show the time. To update the time repeatedly, you need to click the link and then the Back button each time. You might solve this problem by placing the link and the time on the same page. But if the show page becomes very large or complex, redisplaying the whole page is wasteful and can lead to too much complexity.



Back to top


Adding Ajax

Ajax lets you update just a fragment of your Web page. The Rails libraries do most of the work for you. To add Ajax to this application, you need to do four things:

  1. Configure Rails to use JavaScript.
  2. Change the time link to submit a JavaScript Ajax request, instead of simply rendering an HTML link.
  3. Specify the HTML fragment to be updated.
  4. Prepare a place for the updated HTML content.
  5. Build a controller method and possibly a view to render the Ajax response.

To get started, change the code in app/views/ajax/show.rhtml to look like Listing 5:


Listing 5. Changing the show view to use Ajax
<%= javascript_include_tag :defaults %>
<h1>Ajax show</h1>
Click this link to show the current
<%= link_to_remote "time",
:update => 'time_div',
:url => {:action => "time"} %>.<br/>
<div id='time_div'>
</div>

I've made a few changes. First, to handle the configuration, I simply included the requisite JavaScript libraries directly in the view. Usually, I'd have more views, and to avoid repetition I'd include the JavaScript files in a common Rails component, such as a Rails layout. This example has only one view, so I'll keep things simple instead.

Second, I changed the link tag to use link_to_remote. You'll see what this link does in a moment. Notice the three parameters:

  • The link text, which is unchanged from the non-Ajax example.

  • An :update parameter. If you've not seen this syntax before, think of :update => 'time_div' as a named parameter, where :update is the name and update_div is the value. This code tells the Prototype library that the results from this link will update the HTML element with the name time_div.

  • :url => {:action => "time"}, which specifies the URL that the link will invoke. :url takes the value of a hash map. In practice, the hash map has only an element for the controller action: :time. In theory, the URL could also include the name of a controller and any optional parameters the controller might need.

In Listing 5, you can also see the empty div that Rails will update with the current time.

In your browser, load the page http://localhost:3000/ajax/show. Click the link, and you'll see the result in Figure 3:


Figure 3. A view with Ajax
Simple view with Ajax

To get a good feel for what's happening here, view the source for the Web page. Listing 6 shows the code:


Listing 6. The results of the show template, enabled for Ajax
<script src="/javascripts/prototype.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/effects.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/controls.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/application.js?1159113688" type="text/javascript"></script>
<h1>Ajax show</h1>
Click this link to show the current
<a href="#" onclick="new Ajax.Updater(
'time_div', '/ajax/time', {asynchronous:true, evalScripts:true});
return false;">time</a>.<br/>
<div id='time_div'>

</div>

Notice the list of JavaScript includes. The Rails helper -- include_javascript_tags :defaults -- built this list for you. Next, instead of an HTML link, you see a JavaScript function call to build a new Ajax.Updater object. The parameter called asynchronous is set to true, as you would expect. Finally, you see no value within the HTML div tags because the initial page had no value there.



Back to top


Using other Ajax options

Ajax can generate powerful behaviors, even some unexpected ones. For example, my users might not notice the updated time link. The link_to_remote option lets you easily apply special effects to the item so the user notices the result. I'll apply some of the effects now. Change the link_to_remote helper in show.rhtml to resemble Listing 7:


Listing 7. Adding effects
  
<%= link_to_remote "time",
:update => 'time_div',
:url => {:action => "time"},
:complete => "new Effect.Highlight('time_div')" %>

The best Ajax effects draw temporary attention to your change but don't last forever. Your goal should be to alert users to the change without disrupting their workflow. Techniques like this yellow fading highlight, or content that slides in or fades out, won't be permanently distracting.

So far, the link is the only trigger you've seen. Ajax has several others you can use, with some driven by users and others driven by programmatic events, such as a timer. Something like a clock should not necessarily require user intervention. You can update a timer periodically with Ajax with the periodically_call_remote method. Edit the code in show.rhtml to look like Listing 8:


Listing 8. Periodically call the remote method
<%= javascript_include_tag :defaults %>
<h1>Ajax show</h1>
<%= periodically_call_remote :update => 'time_div',
:url => {:action => "time"},
:frequency => 1.0 %>
<div id='time_div'>
</div>

Figure 4 shows the result: a clock that updates at one-second intervals without requiring user interaction:


Figure 4. A clock periodically updated with Ajax
Simple view with Ajax

Though the code in the Rails view is similar to the version without Ajax, the underlying code is much different: this version uses JavaScript instead of HTML. You can see the code in Listing 9 by viewing the source in your browser:


Listing 9. The source for periodically_call_remote
<script src="/javascripts/prototype.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/effects.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/dragdrop.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/controls.js?1159113688" type="text/javascript"></script>
<script src="/javascripts/application.js?1159113688" type="text/javascript"></script>
<h1>Ajax show</h1>
<script type="text/javascript">
//<![CDATA[
new PeriodicalExecuter(function() {new Ajax.Updater(
'time_div', '/ajax/time', {asynchronous:true, evalScripts:true})}, 1.0)
//]]>
</script>
<div id='time_div'>
</div>

Pay close attention to what's happening here. Instead of working with tiny fragments of custom JavaScript, you are effectively working at a higher level of abstraction, and the Ruby on Rails templating system makes the usage model feel quite natural.

As I pointed out earlier, I'm rendering text directly from a controller. That simplification makes it easy to get started but won't hold up over time. My views should handle presentation, and my controllers should marshal data between the view and model. This design technique, called model-view-controller (MVC), makes it easier to isolate changes to a view or model. To enable this application for MVC, I can simply let Rails render the default view, and the contents will replace the previous contents of time-div, just as you'd expect. Change the time method in app/controllers/ajax_controller.rb to resemble the code in Listing 10:


Listing 10. Refactoring
def time
@time = Time.now
end

Change the view in app/views/ajax/time.rhtml to resemble Listing 11:


Listing 11. Using a view to render Ajax content
<p>The current time is <%=h @time %></p>

The controller method sets an instance variable called @time. Because the controller renders nothing explicitly, Rails renders the time.rhtml view. That usage model is exactly the same as rendering a view without Ajax. Once again, you can see that the Rails insulates developers from the differences between applications that use Ajax and those that don't. The usage model is strikingly similar across traditional Web applications and Ajax. More Rails applications take advantage of Ajax because the cost of doing so is so low.



Back to top


Other uses for Ajax in Rails

The Rails Ajax experience is broad and deep -- much deeper than I can cover in a single article or even a series. Rest assured that Rails Ajax support solves some other problems as well. These are some common uses of Ajax in Rails:

  • Submitting remote forms. Ajax forms in Rails work exactly like traditional forms, except you must submit them asynchronously. That means that Forms helper tags in Rails must let you specify a URL to update, and execute visual effects, just as you did with link_to_remote. The Rails submit_to_remote extends a Rails submit helper just as link-to-remote extends the link_to helper.

  • Executing complex scripts. Rails developers often need to execute complex scripts that do more than update a single div and execute effects. Rails provides JavaScript templates for this purpose. With a JavaScript template, you can execute an arbitrary JavaScript script as the result of an Ajax request. Some common uses for these templates, called RJS templates, are updating more than one div, handling form validations, and managing Ajax error scenarios.

  • Completion. You'd often like to offer your users completion, based on items in a database. For example, if the user types Bru, I'd like my application to notice a value of "Bruce Tate" in the database. I can use Ajax to check periodically for changes in a field and send down suggestions for completion as the user types.

  • Dynamically building complex forms. In business, you often need to see part of a completed form before you know which fields a user should complete. For example, a 1040EZ tax form is invalid if a user has certain kinds of income or expenses. With Ajax, you can update the form in progress.

  • Drag and drop. With Rails, you can quickly implement drag-and-drop support with much less effort than most other frameworks require.


Back to top


Conclusion

Ajax is not without its problems. When things go well, the whole experience can be breathtaking. When things break, you may find that debugging takes on a whole new dimension, and debugging techniques and tools still don't match those you'll find in other languages. Ruby on Rails does have one core advantage: simplicity. The Rails wrappers, combined with fantastic community support, make it easy to break into this new world with a very low initial investment. But the Rails support can take you only so far. Two frameworks that do not span the whole Ajax continuum will not satisfy every user.

The Java language has many more Ajax frameworks and approaches to choose from. You can find much greater flexibility, and you'll also find a fantastic support base. But flexibility comes at a price. You'll need to pick not only a strong Ajax framework, but also a Web development framework. For example, integrating the JSF framework is a dramatically different experience from integrating Struts. New technologies often call for simplification. Ajax on Rails may be just the ticket for problems that require the sophistication of Ajax in the UI but none of the advanced enterprise-integration features the Java language provides. Next time, I'll take a deeper look into JavaScript. Until then, keep crossing borders.



Resources

Learn
  • Java To Ruby: Things Every Manager Should Know (Pragmatic Bookshelf, 2006): The author's book about when and where it makes sense to make a switch from Java programming to Ruby on Rails, and how to make it.

  • Beyond Java (O'Reilly, 2005): The author's book about the Java language's rise and plateau and the technologies that could challenge the Java platform in some niches.

  • "Book review: Agile Web Development with Rails" (Darren Torpey, developerWorks, May 2005): Get the scoop on a book that deepens readers' understanding of Rails and the rationale behind agile development approaches.

  • "Ajax: A New Approach to Web Applications" (Jesse James Garrett, Adaptive Path, February 2005): Garrett, who coined the term "Ajax," describes its basic architectural and user experience properties.

  • Scriptaculous and Prototype: The two JavaScript frameworks that power Rails Ajax.

  • Rails Ajax helpers: These helpers shield the Rails developer from the complexities of low-level Ajax programming.

  • Ajax resource center: The developerWorks Ajax portal includes content, blogs, forums and other resources focused on Ajax programming.

  • Ajaxian: This Ajax portal is an excellent discussion of all things related to Ajax.

  • Ajax BluePrints: A discussion of Ajax frameworks and design techniques for the Java programming language.

  • Programming Ruby (Dave Thomas et al., Pragmatic Bookshelf, 2005): A popular book on Ruby programming.

  • The Java technology zone: Hundreds of articles about every aspect of Java programming.


Get products and technologies
  • Ruby on Rails: Download the open source Ruby on Rails Web framework.

  • Ruby: Get Ruby from the project Web site.


Discuss


About the author

Bruce Tate

Bruce Tate is a father, mountain biker, and kayaker in Austin, Texas. He's the author of three best-selling Java books, including the Jolt winner Better, Faster, Lighter Java. He recently released From Java to Ruby and Rails: Up and Running. He spent 13 years at IBM and later formed the RapidRed consultancy, where he specialized in lightweight development strategies and architectures based on Ruby, and in the Ruby on Rails framework. He is now the CTO of WellGood LLC, a company that is forming a marketplace for nonprofit organizations and charitable giving.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics