What's New in Rails 2.x

New features have been added to Rails 2.0 and 2.1


August 26, 2008
URL:http://www.drdobbs.com/web-development/whats-new-in-rails-2x/210200763

Deepak is a Sun Certified Java 1.4 Programmer and Sun Certified Web Component Developer for J2EE.


Rails is an open-source framework for developing web applications. Release 2.0, a major update to the Rails framework, was made available in December 2007 and includes a load of new features and fixes. More recently this was followed by Rails 2.1 (available for download here). In this article, I examine some of the major new features in Rails 2.x.

To install Rails 2.x, simply run the following command:


gem install rails -y

The output from the command (Figure 1)shows that the most recent version, Rails 2.1, has been installed. The rails 2.1.0, activesupport-2.1.0, activerecord-2.1.0, actionpack-2.1.0, actionmailer-2.1.0, and activeresource-2.1.0 gems get installed.

[Click image to view at full size]
Figure 1: Installing Rails.

Rails Web Services

RESTful web services have additional support, while the ActionWebService gem has been removed from the default package. ActiveResource gem has been added to the default bundle. In Rails 2.0 RESTful routes use a new custom delimiter. For example, a custom action route is defined as follows:


map.resources :catalog, :collection => { :entry => :get }

Before Rails 2.0, the resulting route uses a semicolon (;) to delimit the custom action:


GET /catalog;entry

In Rails 2.1 you use the standard forward slash (/):


GET /catalog/entry

In Rails 2.1, nested REST resources have been replaced with has_one and has_many to define resource associations. For example, associations between resources using the nested resources is defined as follows in config/routes.rb:


map.resources :catalogs do |catalogs|
  posts.resource :journal
  posts.resource :edition
  posts.resources :entries
end

In the example, the catalogs resource is mapped to journal, edition, and entries resources. Using has_one and has_many, the associations between resources may be defined as follows:


map.resources :catalogs, :has_one => [:author,:edition],:has_many => [:entries]

Named prefixes in nested resources is no longer required in Rails 2.0. Previously you had to specify a named prefix using the name_prefix option as follows:


map.resources :catalogs do |catalogs|
  catalogs.resources :entries, :name_prefix => "catalog_"
end

In Rails 2.0 named prefix is implicit. For example, the following nested resource provides a helper method catalog_entries_url(catalog_id):


map.resources :catalogs do |catalogs|
  catalogs.resources :entries
end

If you don't want the named prefix to be implicit set name_prefix to nil explicitly.


map.resources :catalogs do |catalogs|
  catalogs.resources :entries, :name_prefix => nil
end

In Rails 2.0 the namespace feature (map.namespace) has been added to the routing resources. Using the namespace feature, an admin interface may be defined like this:


map.namespace(:admin) do |admin|
  admin.resources :journals,
    :collection => { :catalog => :get },
    :member     => { :duplicate => :post },
    :has_many   => [ :articles, :images ]
end

The admin interface generates the admin_journals_url, which points to "admin/journals" and looks for the Admin::JournalsController. Corresponding to the has_many relationship the admin_journal_articles_url, which points to "admin/journals/#{journal_id}/articles" and looks for Admin::ArticlesController, is also created. The "rake routes" task has been added to list all the named routes. A new feature in ActiveResource is that the ability to invoke custom methods has been added. Consider a REST web service that has the standard CRUD-based actions for a Employee class including a custom element method promoted and a custom collection method sorted. The ActiveResource class Employee is defined as follows:

 

class Employee < ActiveResource::Base
  self.site = "http://employeeblog.com/"
end

The custom methods are invoked using one of GET, POST, PUT, or DELETE. For a collection custom method the get/post/put/delete is invoked on the class and for a element custom method the get/post/put/delete is invoked on an instance of the class. You would invoke the collection custom method sorted with the following URI:


GET /employees/sorted.xml?by=first_name

In the ActiveResource, the collection method sorted is invoked this way:


employees = Employee.get(:sorted, :by => 'first_name')

The custom collection method sorted is specified as the first argument to the get method. Similarly the custom element method promoted is invoked with the following URI:


PUT /employees/1/promoted.xml?position=Manager

In the ActiveResource the custom element method promoted is invoked by specifying the method as the first argument to the put method:


steve = Employee.find(1)
steve.put(:promoted, :position => 'Manager')

The ActiveResource find method supports a new option called :from for a custom method or a resource. The first argument to the find method specifies a resource id or the scope (:all, :first, :one). For example, all the recent catalog entries can be found as follows:


Catalog.find(:all, :from => :recent)

ActiveResource also supports custom headers using the headers option. In the following example, every request from Catalog would include the specified header:

 

class Catalog < ActiveResource::Base
  headers['X-MyHeader'] = 'steve'
end

Multiple Views Support

The ActionPack has added support for multiviews. The .rhtml files have been replaced with .erb files and the .rxml files have been replaced with .builder files; the show.rhtml file becomes show.html.erb and the show.rxml file becomes show.xml.builder. The .erb and .builder templates may be used to render more than just HTML and XML format files. The format of the template has been separated from the rendering engine. The new format for view templates is action.format.renderer. For example, you are designing the iPhone and mobile versions of your website and you want both the versions to serve text/html. First, you would be required to register the iphone and mobile formats in the /config/initializers/mime_types.rb file as follows:


Mime::Type.register_alias "text/html", :iphone   
Mime::Type.register_alias "text/html", :mobile  

Using multiviews the index.html.erb, index.iphone.erb and index.mobile.erb templates would all serve text/html. Similarly you could serve csv files such as show.csv.erb by registering the text/csv format. If you want to run Atom feed view templates, first you would register the application/atom+xml type.


Mime::Type.register_alias "application/atom+xml", :atom

View template index.atom.builder would render the index action for the atom feed. Previously the view template would have been called index.rxml.

Improvements in Fixtures

Prior to Rails 2.0 setting up fixtures for model classes with associations between them involved specifying fixture ids. Consider the following model in which the Catalog class has a 1:many association with the Journal class:


class Catalog < ActiveRecord::Base; has_many :journals; end
class Journal < ActiveRecord::Base; belongs_to :catalog end

The fixture file catalog.yml corresponding to the Catalog class is as follows:


catalog1:
  id: 1
  edition: January 2009
  Publisher: Dr. Dobb's

The fixture file journals.yml has a reference to the catalog id.


journal1:
  id: 1
  name: JavaDept
  catalog_id: 1

journal2:
  id: 2
  name: Dr. Dobb's
  catalog_id: 1

In Rails 2.0 fixture ids and references to fixture ids are not needed. In Rails 2.0 the catalog.yml fixture file is specified as follows:

 

catalog1:
  edition: January 2009
  Publisher: Think Services 

And, the journals.yml fixture file is defined without the id references as follows:


journal1:
  name: JavaDept
  catalog: catalog1

journal2:
  name: Dr. Dobb's
  catalog: catalog1

Another new fixtures feature is that multiple fixtures may be referred in a single fixtures invocation. For example, fixtures catalog1 and catalog2 may be invoked using the assert_equal method as follows:


fixtures :catalogs
 ...
assert_equal catalogs(:catalog1, :catalog2), Catalog.find(:all)

Prior to Rails 2.0 multiple fixtures invocations had to be specified. For example, the previous assert_equal statement is specified as follows:


fixtures :catalogs
 ...
assert_equal [catalogs(:catalog1), catalogs(:catalog2)], Catalog.find(:all)

Performance of fixtures has been greatly improved to increase the performance of test suites by 50-100 percent.

Better Exception Handling

It is common to redirect the user or render specific pages for specific exceptions. Rails 2.0 has added support for the ActionController::Base.rescue_from method, which provides a cleaner style than the case statement-based rescue_action_in_public. For example, different files are rendered for different exceptions using the rescue_action_in_public method as follows:


class CatalogsController < ApplicationController
  def rescue_action_in_public(exception)
    case(exception)
      when ActiveRecord::RecordNotFound then render :file => '/bad_record'
      when NoMethodError then render :file => '/no_method'
      else render :file => '/error'
    end
  end
end

Using the rescue_from method the different exceptions may be mapped to different handler methods as follows:


class CatalogsController < ApplicationController

  # Declare exception to handler methods
  rescue_from ActiveRecord::RecordNotFound, :with => :bad_record
  rescue_from NoMethodError, :with => :show_error

  def bad_record; render :file => '/bad_record'; end
  def show_error(exception); render :text => exception.message; end
end

The rescue_from method accepts a block or a proc to specify exception handling.

Efficient Migrations

Rails 2.0 provides an alternative, more efficient form of declaring migrations:


create_table :catalog do |t|
  t.column, "catalog_id",  :integer
  t.column, "journal",  :string, :null => false
  t.column, "publisher",   :string, :null => false
  t.column, "edition", :string, :null => false
  t.column, "title",  :string, :null => false
  t.column, "author",  :string, :null => false
end

In Rails 2.0, you specify the following:


create_table :catalog do |t|
  t.integer :catalog_id
  t.string  :journal, :publisher,:edition,:title,:author :null => false
end

New ActiveRecord Features

In Rails 2.0 active record cache is enabled by default for all controller actions. Query Cache has been added in Rails 2.0 to return cached results for similar SQL calls. For example, in the following action definition the SQL statement would be run twice against the database in earlier versions of Rails; in Rails 2.0 the SQL statement would run once and be loaded from cache in the second call.


class CatalogController < ApplicationController
  def getCatalogEntries
      catalog = Catalog.find(1)
       ...
      catalog_again = Catalog.find(1)
  end
end

If you have been using Rails with commercial databases you have to install the commercial database adapters as they are not included in the Rails distribution. Only database adapters for the open source databases MySQL, SQLite, and PostgreSQL are included in the Rails distribution. If you do have to use a commercial database simply run the gem install command for the database.


gem install activerecord-oracle-adapter
gem install activerecord-sqlserver-adapter
gem install activerecord-firebird-adapter
gem install activerecord-frontbase-adapter
gem install activerecord-openbase-adapter
gem install activerecord-sybase-adapter

Cleaner Environment File

In Rails 2.0 the config/initializers directory has been added from which all Ruby files are automatically loaded after the Rails configuration is completed and the Rails::Initializer has run. The config/initializers directory feature makes environment.rb file a lot more cleaner as the various configs are not required to be declared in the environment.rb file. For example, if you needed to declare some action mailer configs and date formats you would add the following config statements to environment.rb:


ActionMailer::Base.delivery_method = :sendmail
ActionMailer::Base.default_charset = "utf-8"
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(:concise => "%d.%b.%y")
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(:medium => "%b %e, %Y"

With the config/initialzers directory feature create a config/initializers/mail.rb file with the following configs and the mail.rb files gets loaded automatically:

 

ActionMailer::Base.delivery_method = :sendmail
ActionMailer::Base.default_charset = "utf-8"

Similarly create a config/initializers/date_formats.rb file with the following date formats:


ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(:concise => "%d.%b.%y")
ActiveSupport::CoreExtensions::Date::Conversions::DATE_FORMATS.merge!(:medium => "%b %e, %Y"

Rails 2.0 includes the config/initializers/inflections.rb file for the pluralization rules and the mime_types.rb file for the mime types.

Misc Features

Some simplifications have been made to controller and view methods involving URLs. Record identification has been made easier in Rails 2.0. Conventions have been added to map model classes to resource URLs. For example, 'catalog' is a Catalog object that by convention will be mapped to catalog_url.

A new module for HTTP Basic Authentication has been added to Rails 2.0. The ActionPack includes new security features to prevent cross site scripting and cross site references. Session storage is easier to maintain in Rails 2.0 using cookies instead of a file system on the database. ActionPack includes a new request profiler to speed up an application. ActionPack includes a AtomFeedHelper, which makes it easier to create Atom feeds using an enhanced Builder syntax. For better testing assert_difference has been added to the ActiveSupport and assert_emails has been added to ActionMailer. The debugger has returned in Rails 2.0. All that is required to use the debugger is install the ruby-debug gem, put "debugger" in the application, and start the server with debugger or -u. Source-annotations extractor tasks have been added to rake. All helpers from app/helpers/**/*.rb are automatically included in the ApplicationController. Some new options have been added to the render method to improve rendering. Layouts have been added to partials. ActiveSupport::BufferedLogger has been added as new default logger for better logging performance. Rails 2.0 has the provision to specify the plugin loading order. The allow_blank option has been added to active record validation methods to allow blank values. For all the changes in Rails 2.0, see the Rails CHANGELOGS.

What's New In Rails 2.1

Support for time zones has been added in Rails 2.1. Just specify the time zone using the Time.zone variable and all date references will use the specified time zone. The time zone may be set in the controller using a before filter:


class ApplicationController < ActionController::Base
  before_filter :set_timezone
  def set_timezone
    Time.zone = "London"
  end
end

With the timezone specified in the controller, all controller actions and views will use the specified time zone. The default time zone may be set in environment.rb:


Rails::Initializer.run do |config|
  config.time_zone = "Pacific Time"
end

In Rails 2.1, provision has been added to track changes in ActiveRecordobjects. Rails 2.1 has also added the provision to specify gems that are required by the Rails application. The gems may be specified using config.gem and when the application loads it will find and require the specified gems. The following environment.rb specifies the requird gems:


Rails::Initializer.run do |config| 

  # Require the latest version of activerecord-sqlserver-adapter
  config.gem "activerecord-sqlserver-adapter"

  # Require a specific version of activerecord-oracle-adapter
  config.gem "activerecord-oracle-adapter", :version => '1.0'

  # Require a gem from a non-standard source
  config.gem "sybase-adapter", :source => "http://www.sybase-adapter.net"
end

Also rake tasks have been added to install, build, package, and unpackage gems. The named_scope feature has been added to make it easier to create reusable SQL queries. Naming convention has been added to Rails migrations to name the migrations based on unique UTC based timestamp. Caching has been improved in Rails 2.1 in which custom controller caching mechanism may be specified.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.