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:


12) Get elements with CSS selectors:

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|



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'


Minor bug in RJS sample

Bill Mitchell's picture


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.

Linux Journal

All the new OSs and windowing systems are oriented towards content consumption instead of content production.

--Steve Daniels 2013

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


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?

All the new OSs and windowing systems are oriented towards content consumption instead of content production.

--Steve Daniels 2013