At the Forge - Ruby on Rails 3

What's new in Ruby on Rails 3, and what has stayed the same? Reuven explores the latest version of this framework and what it means for you.

you now can say this:

validates :email, :presence => true, :uniqueness => true

I'm still not sure which of these syntaxes I prefer. Fortunately, at least for now, the old syntax still works and doesn't raise a deprecation warning.

Under the hood, there have been a bunch of changes to Active Record. Active Relation is probably the biggest and most obvious, but another is the modularization of Active Record, such that validations now are in a separate module. This probably won't affect most people, but it means if you develop a different ORM, or if you're implementing an interface to a non-relational (NoSQL) database, such as MongoDB, you now can use the validation system from Active Record without having to re-invent the wheel.

Overall, Active Record 3 continues to shine. It's one of my favorite reasons for using Rails, and I know I'm not alone in my appreciation for all the things it does to help my applications keep humming along.


Perhaps the biggest change you are likely to encounter in Rails 3 is Bundler. One of the best things about programming in Ruby is the huge library of gems, or downloadable packages, available to the community. This is Ruby's answer to Perl's huge CPAN library, and although Ruby gems aren't even close to the size and scope of CPAN, they are being developed at an impressive pace.

Earlier versions of Rails attempted to handle the inclusion of gems inside the main configuration file, config/environments.rb. In this file (or any of its environment-specific files), you would put a line that looked like this:

config.gem 'will_paginate"

Doing so would ensure that the will_paginate gem is available and included. A number of Rake tasks were defined to automate the process of testing for installed gems, installing them on the system and installing them in the application.

Rails 3 changes all of this, in favor of a program called Bundler. The idea is that you create a file, called Gemfile, in the root directory of your Rails application. You then invoke bundle install, which goes through your Gemfile, ensures that all of the gems are indeed installed and creates a file called Gemfile.lock that specifies the precise versions that need to be installed for the application to run. Together, the Gemfile and Gemfile.lock files help ensure that the gems you need are installed on both your development and production machines, either in the system's gem directory or privately in the application.

I must admit that I'm still getting used to Bundler, and I haven't yet become convinced of how wonderful it is or how superior it is to the previous way we configured gems. I'm also more likely than not to forget to type bundle install before running my server.

That said, I do see an advantage to having all gem requirements and configurations, regardless of environment, in a single file. It certainly makes deployment easier on such hosting systems as Heroku, and it avoids some of the confusion I've experienced with various gems being required in different environments. This is perhaps the only feature of Rails 3 that has yet to overwhelm me with its advantages, but the pain of switching to Bundler is relatively small, and I have a feeling I'll become convinced over time that it's useful and even superior.


The last major change in Rails 3 that I cover here is routing. The router is the part of Rails that maps HTTP requests to controller methods. If a user sends a request of GET /people/5, it's up to the router to determine that the people controller's show method has an ID of 5.

For several years now, Rails has tried to simplify routing by encouraging the use of REST (representational state transfer). That is, each URL describes a particular object, and it is the HTTP verb (GET, POST, PUT, DELETE) that describes what you want to do to that object. If I just want to see person #5, I can say:

GET /people/5

But, if I want to update person #5, I would say:

PUT /people/5

along with name-value pairs describing the attributes that should be updated.

In Rails 2, you would describe a resource in the routes file (config/routes.rb) with a line like this:

map.resources :people

In Rails 3, things have gotten simpler. For starters, you can declare a resource as follows:

resources :people

In and of itself, that's not a big change. But, if you need to add additional methods beyond the standard seven (index, show, new, create, edit, update and destroy) Rails provides, you can do so in a block:

resources :people do
  post "send_feedback", :on => :collection

This was certainly possible with the older syntax, but it was a bit more convoluted.

If you simply want to add a single, hard-coded route, you can do it with:

get "home/faq"

Rails 3 is smart enough to know this means you want GET requests for /home/faq to be redirected to the home controller and to invoke the faq method.

I must admit that Rails routing always seemed like a bit of black magic to me, even after years of working with it. The simplification that Rails 3 offers is most welcome, in that I feel I have a much better understanding of what it does and how it accomplishes it. Best of all, my routes.rb file has become less complex and easier to maintain, which is, as I mentioned previously, one of the biggest reasons for working with Rails.