In association with heise online

23 August 2011, 15:00

From Rails 2.3 to 3.0

by J. Austin Hughey

In this, the first of two articles leading up to the release of Rails 3.1, expected on 30 August, web applications engineer J. Austin Hughey discusses the changes made and new features that were added to Rails between versions 2.3 and 3.0. In the second article he will discuss the new features and improvements coming in version 3.1.

The impending release of version 3.1 of the Ruby on Rails web application development framework has a lot of developers wondering, "should I upgrade?" With so many new features and performance improvements, the impulse can be rather strong, especially for those on applications built on version 2.3.x. While upgrading isn't recommended in all cases, this article should provide you with an overview of the changes to Rails since 2.3, starting with 3.0 and, in the next article, moving onto what's planned for version 3.1.

From 2.3.x to 3.0

Rails 3.0 saw the introduction of many features designed to make the framework more secure and improve its overall robustness.

ActiveRecord, ActiveModel and ActiveRelation

ActiveRecord has been refactored as a series of three different classes working together: ActiveRecord, ActiveModel, and ActiveRelation.

ActiveRecord is still the core ORM that we've been familiar with for years. It processes all queries as it did in previous versions of Rails, albeit with a different syntax which we'll return to later.

ActiveModel is an "extraction" of various modules that were once embedded into ActiveRecord. Validations, i18n translation, serialisation, and other "goodies" have been placed into a new class called ActiveModel. This separation of concerns allows you to make standard Ruby classes "feel like" ActiveRecord by including the appropriate ActiveModel modules, and then using their features, e.g. model validations.

For example, if you wanted to create a plain Ruby object, but use ActiveModel validations, you could do so like this:

require 'rubygems'
require 'active_model'

class Automobile
# Make use of validations
include ActiveModel::Validations

attr_accessor :num_wheels, :transmission_type, :engine_type,
:fuel_type, :mpg

validates :num_wheels, :numericality => true
validates :transmission_type, :presence => true
validates :engine_type, :presence => true
validates :fuel_type, :presence => true,
:inclusion => { :in => ['Diesel', 'Gasoline', 'Hydrogen', 'Electric Battery'] }
validates :mpg, :presence => true, :numericality => true,
:if => :liquid_fuel?

private

def liquid_fuel?
return true if ["Gasoline", "Diesel"].include?(fuel_type)
return false
end
end

As you can see, even though this class doesn't inherit from ActiveRecord::Base, by including ActiveModel::Validations, we have access to all the functionality that previously required the whole of ActiveRecord to use. We even have access to conditional validations without any ActiveRecord dependence whatsoever.

More Information about ActiveModel can be found in Yehuda Katz' (@wycats) article, "Make Any Ruby Object Feel Like ActiveRecord", as well as in the various ActiveModel modules listed in the Rails API documentation, such as ActiveModel::Serialization, ActiveModel::Validations, and ActiveModel::Translation, to name a few.

ActiveRelation is a new system for handling database queries based on relational algebra, and allows for a much cleaner query syntax in addition to performance improvements through lazy loading. For an example of the differences between Rails 2.3 and 3.0's querying syntaxes, see the following examples:


Zoom The more compact syntax of Rails 3.0 queries

As you can see, the Rails 3 syntax is a bit shorter. One of the more notable differences in this situation, however, is that while the Rails 2.3 example above would return a Ruby array object, the Rails 3.0 example would return an ActiveRecord::Relation object. This allows us to perform method chaining on the AREL object, calling methods such as #first, #limit, and so on. Those that would normally be caught by Enumerable are overridden so that they operate on the query itself, and not on the results of that query. For example:

# Rails 2.3
Model.find(:all, :conditions => {:something => "value"}).first
# (This is bad, don't do it! Only here as an example.)

# Rails 3
Model.where(:something => "value").first

In the Rails 2.3 example, all rows matching our query would be returned as an array, and then the first element of that array would be returned. Note that this is a bad practice, and shouldn't be used outside the scope of documentation and/or explanation (use Model#first for 2.3.x ActiveRecord instead).

By contrast, the Rails 3 example would return an ActiveRecord::Relation object, and it's on this object that we call #first. Because #first is defined in a module included in ActiveRecord::Relation, it uses that method instead of the standard Enumerable #first method. The #first method used will modify the query before its execution because AREL objects are now [u]lazy loaded[/u]. The Rails 3 example above would generate SQL similar to: "SELECT * FROM models WHERE something = 'value' LIMIT 1;". Note that you can also use methods such as #limit, #order, and others on a single ActiveRecord::Relation object.

# Rails 2.3
Model.all(:conditions => {:something => "value"}, :limit => 5)
# Rails 3
Model.where(:something => "value").limit(5).order("something ASC")

Next: New Routing System

Print Version | Permalink: http://h-online.com/-1285884
  • Twitter
  • Facebook
  • submit to slashdot
  • StumbleUpon
  • submit to reddit
 


  • July's Community Calendar





The H Open

The H Security

The H Developer

The H Internet Toolkit