Rails Writ Large

Ruby on Rails 1.1 and the paradox of how constraints can lead to greater freedom.
Rails 1.1

The first public release of Ruby on Rails was version 0.5, in July 2004. More than a year later (and with nearly every line of code changed) Ruby on Rails 1.0 was announced in December 2005. That milestone was preceded by an intense push of polishing and testing to ensure that it was a solid release—so you might expect that the Rails Core team has coasted down the tracks since then, enjoying the phenomenal success of its software.

You might expect that, but you'd be wrong. In fact, they haven't slowed down one bit, and the next major release of Rails has just been announced. It's the biggest release to date, with more than 500 enhancements, fixes and tweaks. The majority of the 500 changes subtly polishes existing features, but some of them are superstars that promise to change the way your applications are developed. I've poured through the change logs to find the most interesting parts, and they can be lumped into three major groups: powerful Ajax, richer domain models and easy Web services.

Powerful Ajax

Arguably, the most significant new features in Rails 1.1 redefine the way Rails handles Ajax. Rails already had top-notch support for creating Ajax applications—it works by sending small snippets of HTML to a page to be inserted. Now, it also can return JavaScript to the browser to be evaluated. That means updating more than one page element in one step is a snap.

The kicker is that instead of writing the JavaScript by hand, it can be generated by Rails, using Ruby syntax. That's where RJS, Ruby-generated JavaScript, comes into play. In addition to .rhtml (Ruby HTML) templates, you can create .rjs (Ruby JavaScript) ones. In them, you can write Ruby code that will generate JavaScript code, which is sent as the result of an Ajax call and evaluated by the browser.

Let's look at an example to see how this can be used. The on-line store IconBuffet uses RJS for its shopping cart (see www.iconbuffet.com/products/amsterdam to try it out). When a product is added to the cart, three separate page elements need to be updated to reflect the change. Before RJS, that would entail a dozen lines of JavaScript and multiple round-trips to the server. But now, it can be accomplished in one pass, with no custom JavaScript.

Figure 1. Add an Item to the Cart

The Add to Cart button uses the standard Ajax link helper, just like before:


<%= link_to_remote "Add to Cart", :url => { :action =>
 "add_to_cart", :id => 1 } %>

Clicking the link triggers the add_to_cart action, which updates the session and renders its template, add_to_cart.rjs:


page[:cartbox].replace_html :partial => 'cart'
page[:num_items].replace_html :partial => 'num_items'
page["product_#{params[:id]}"].addClassName 'incart'

The template is rendered into JavaScript that is sent back to the browser and evaluated, which updates the three page elements accordingly. You may be wondering where this page object came from—it's passed to RJS templates to represent JavaScriptGenerator, and it has many tricks up its sleeve:

1) Pop a JavaScript dialog box:

page.alert 'Howdy'

2) Replace the outerHTML of an element:

page.replace :element, "value"

3) Replace the contents of an element:

page.replace_html :element, "value"

4) Insert text:


page.insert_html :bottom, :list, '<li>Last item</li>'

5) Simulate a redirect with:

window.location.href: page.redirect_to url_for(...)

6) Call a JavaScript function:

page.call :alert, "Hello"

7) Assign to a JavaScript variable:

page.assign :variable, "value"

8) Call an effect:

page.visual_effect :highlight, 'list'
page.visual_effect :toggle, "posts"
page.visual_effect :toggle, 'comment', :effect => :blind

9) Show an element:

page.show 'status-indicator'

10) Hide elements:

page.hide 'status-indicator', 'cancel-link'

11) Refer to an element by ID:

page['blank_slate']
page['blank_slate'].show

12) Get elements with CSS selectors:

page.select('p')
page.select('p.welcome b').first
page.select('p.welcome b').first.hide

13) Insert some JavaScript:


page << "alert('hello')"

14) Make a draggable:

page.draggable 'product-1'

15) Make a droppable:

page.drop_receiving 'wastebasket', :url => { :action => 'delete' }

16) Make a sortable:

page.sortable 'todolist', :url => { action => 'change_order' }

17) Delay execution:

page.delay(20) { page.visual_effect :fade, 'notice' }

Enumerable methods also can be used, and they'll generate the equivalent JavaScript code:

page.select('#items li').collect('items') do |element|
              element.hide
      end

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

toggle's code doesn't work for me

Bart's picture

point 8) code doesn't work for me. Browser (FF/IE) complains with RJS error (RerefenceError:'blind_down' is not defined). Here are my *.rjs files

caused problem:
page.visual_effect :toggle_blind, 'element', :effect => 'blind_down'

works fine:
page.visual_effect :toggle_blind, 'element'

Bart

Minor bug in RJS sample

Bill Mitchell's picture

www.iconbuffet.com/products/amsterdam

Click "add to cart", then click "remove from cart". Now try to click "add to cart." You can't because the buttons still say "remove." Buttons fail to refresh after removing from cart. Must reload page to see the add to cart button again.

This page displays too wide, requires horizontal scrolling for e

Randy Kramer's picture

This page displays too wide, requires horizontal scrolling for each line. I haven't tried to pinpoint the cause of the trouble.

You should limit lines to something around 80 characters, and/or make them (lines) wrap to the width of the page.

This page displays too wide

Keith Daniels's picture

I can't replicate this problem. I tested at 800x600 resolution and though the gray code blocks had horizontal scroll bars none of the body text was outside of the screen.

What browser are you using, what screen resolution and what operating system. It would also help if you would check that you have not changed any of you browser settings so that they override the style sheets on the web site.

Webmaster
Linux Journal

"I have always wished that my computer would be as easy to use as my telephone.
My wish has come true. I no longer know how to use my telephone."
-- Bjarne Stroustrup

print version runs off the line

bumparocky's picture

too wide for printing also....
print preview in the latest firefox, of the printer friently version, shows the lines getting chopped off

rocky

print version runs off the line

Keith Daniels's picture

Re: too wide for printing also....

Does the "also" imply that the horizontal scroll bars appear as well -- during regular viewing?

I too have the latest version of FireFox and the priter friendly version looks fine in FireFox's print preview.

The print preview of the regular web page does look funny but I think that is a FireFox problem dealing with complex multi column pages instead of a site problem.

Are you using the Windows version of FireFox? If not which Linux version are you using and what is the FireFox version?

"I have always wished that my computer would be as easy to use as my telephone.
My wish has come true. I no longer know how to use my telephone."
-- Bjarne Stroustrup

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState