CSC/ECE 517 Fall 2011/ch2 2f vh: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 13: Line 13:
Application in Rails 2. It is assumed that readers are familiar with Rails 2. With this, it serves as a
Application in Rails 2. It is assumed that readers are familiar with Rails 2. With this, it serves as a
quick tutorial to understand Rails 3 features.
quick tutorial to understand Rails 3 features.
==Structural==
===Structural===
===Ruby Version===
====Ruby Version====
Rails 3.0 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been
Rails 3.0 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been
dropped officially and you should upgrade as early as possible. Rails 3.0 is also compatible with Ruby
dropped officially and you should upgrade as early as possible. Rails 3.0 is also compatible with Ruby
1.9.2.
1.9.2.
===Modularization===
====Modularization====
Versions prior to Rails 3 were strongly coupled to a limited choices of frameworks that formed the
Versions prior to Rails 3 were strongly coupled to a limited choices of frameworks that formed the
Rails stack. For example, a standard Rails stack used Active Record as its ORM layer, Action View for
Rails stack. For example, a standard Rails stack used Active Record as its ORM layer, Action View for
Line 26: Line 26:
behave like regular plugins. This allows other plugins, like DataMapper, to use exactly the same APIs
behave like regular plugins. This allows other plugins, like DataMapper, to use exactly the same APIs
used by ActiveRecord and hence replace it if the end user desires..
used by ActiveRecord and hence replace it if the end user desires..
===Active Record===
====Active Record====
Change in query interface:
Change in query interface:
In Rails 2, ActiveRecord provides the following finder methods :
In Rails 2, ActiveRecord provides the following finder methods :
Line 63: Line 63:
the use of Arel, now returns relations on its core methods.
the use of Arel, now returns relations on its core methods.
ActiveRecord in Rails 3 will have the following new finder methods.
ActiveRecord in Rails 3 will have the following new finder methods.
<ul>
<ul>
<li>where (:conditions)</li>
<li>where (:conditions)</li>
Line 77: Line 78:
<li>from</li>
<li>from</li>
</ul>
</ul>
All of the above methods returns a Relation. All these methods are defined on the Relation object as
All of the above methods returns a Relation. All these methods are defined on the Relation object as
well, making it possible to chain them.
well, making it possible to chain them.
<pre>
<pre>
vaibhav = User.where(:name => 'vaibhav')
vaibhav = User.where(:name => 'vaibhav')
new_users = User.order('users.id DESC').limit(20).includes(:items)
new_users = User.order('users.id DESC').limit(20).includes(:items)
</pre>
</pre>
The relation returned also supports the following methods:
The relation returned also supports the following methods:
You could call any of the following methods on a relation :
You could call any of the following methods on a relation :
<ul>
<ul>
<li>new(attributes)</li>
<li>new(attributes)</li>
Line 98: Line 103:
<li>exists?</li>
<li>exists?</li>
</ul>
</ul>
For example, in cookbook application
For example, in cookbook application
In rails 2 for fetching all categories which have pizza we execute statement
In rails 2 for fetching all categories which have pizza we execute statement
<pre>
<pre>
Category.find(:all, :conditions => {:recipe =>’pizza’})
Category.find(:all, :conditions => {:recipe =>’pizza’})
Line 107: Line 114:
Category.where(:recipe => ‘pizza’)
Category.where(:recipe => ‘pizza’)
</pre>
</pre>
===Active Model Abstraction===
 
====Active Model Abstraction====
Active Model was extracted while decoupling Rails’ historic connection between ActiveRecord, its
Active Model was extracted while decoupling Rails’ historic connection between ActiveRecord, its
default ORM, and ActionPack, its controller and view layer. All new ORM plugins (e.g. DataMapper or
default ORM, and ActionPack, its controller and view layer. All new ORM plugins (e.g. DataMapper or
Line 118: Line 126:
is the use of validations (traditionally an Active Record feature) in any Ruby object that adheres to the
is the use of validations (traditionally an Active Record feature) in any Ruby object that adheres to the
Active Model API.
Active Model API.
<pre>
<pre>
class Person < ActiveRecord::Base
class Person < ActiveRecord::Base
Line 123: Line 132:
end
end
</pre>
</pre>
To do the same thing for a plain old Ruby object, simply do the following:
To do the same thing for a plain old Ruby object, simply do the following:
<pre>
<pre>
class Person
class Person
Line 134: Line 145:
end
end
</pre>
</pre>
For example, In Cookbook application discussed in class we have the recipe model class with
For example, In Cookbook application discussed in class we have the recipe model class with
validations (Rails 2.x code)
validations (Rails 2.x code)
<pre>
<pre>
class Recipe < ActiveRecord::Base
class Recipe < ActiveRecord::Base
Line 144: Line 157:
end
end
</pre>
</pre>
In Rails 3 we achive the same functionality by less code and has validates_presence_of method
In Rails 3 we achive the same functionality by less code and has validates_presence_of method
<pre>
<pre>
class Recipe
class Recipe
Line 152: Line 167:
end
end
</pre>
</pre>
Some other modules available in Active Model include:
Some other modules available in Active Model include:
<ul>
<ul>
Line 160: Line 176:
<li>Observing: ActiveRecord-style observers</li>
<li>Observing: ActiveRecord-style observers</li>
</ul>
</ul>
===Action Controller===
====Action Controller====
Previously, ActionController had a number of disparate elements all in one place. This monolithic
Previously, ActionController had a number of disparate elements all in one place. This monolithic
component is now divided into multiple pieces. Two significant componets are:
component is now divided into multiple pieces. Two significant componets are:
ActionDispatch
=====ActionDispatch=====
The dispatcher functionality has been moved into ActionDispatch, with the code inside tightened
The dispatcher functionality has been moved into ActionDispatch, with the code inside tightened
up and really made a conceptual component. This has resulted in a new routing API. While the old
up and really made a conceptual component. This has resulted in a new routing API. While the old
Line 193: Line 209:
The :as in the above example specifies a named route, and creates the homepage_url et al helpers as
The :as in the above example specifies a named route, and creates the homepage_url et al helpers as
in Rails 2.
in Rails 2.
'''Examples'''
 
Simple routes:
'''Simple routes'''
Rails 2
Rails 2
<pre>
<pre>
Line 225: Line 241:
root :to=>”user#index”
root :to=>”user#index”
</pre>
</pre>
Legacy Route:
'''Legacy Route'''
Rails 2
Rails 2
<pre>
<pre>
Line 235: Line 251:
Match ':controller(/:action(/:id(/:format)))
Match ':controller(/:action(/:id(/:format)))
</pre>
</pre>
===AbstractController===
====AbstractController====
Rails 3 has refactored ActionController and ActionMailer to inherit from a common superclass:
Rails 3 has refactored ActionController and ActionMailer to inherit from a common superclass:
AbstractController. AbstractController includes the basic concept of controllers, rendering, layouts,
AbstractController. AbstractController includes the basic concept of controllers, rendering, layouts,
Line 242: Line 258:
HTTP. This AbstractController handles the basic notion of controllers, actions, and action dispatching,
HTTP. This AbstractController handles the basic notion of controllers, actions, and action dispatching,
and not much else.
and not much else.
==Development==
===Development===
===Rails generator system===
====Rails generator system====
The new script/rails replaces all the scripts that used to be in the script directory. You do not run script/
The new script/rails replaces all the scripts that used to be in the script directory. You do not run script/
rails directly though, the rails command detects it is being invoked in the root of a Rails application and
rails directly though, the rails command detects it is being invoked in the root of a Rails application and
Line 252: Line 268:
! Rails 3
! Rails 3
|-
|-
| row 1, rails script/generate
| rails script/generate
| row 1, rails g
| rails g
|-
|-
| row 2, rails script/console
| rails script/console
| row 2, rails c
| rails c
|-
|-
| row 3, rails script/server
| rails script/server
| row 3, rails s
| rails s
|-
|-
| row 3, rails script/dbconsole
| rails script/dbconsole
| row 3, rails db
| rails db


|}
|}
===JS library support===
====JS library support====
Rails 2 shipped with prototypejs as the default javascript library. However, Rails 3 makes it very easy
Rails 2 shipped with prototypejs as the default javascript library. However, Rails 3 makes it very easy
to pick a javascript library of choice, for example you can now use jquery as the base javascript library.
to pick a javascript library of choice, for example you can now use jquery as the base javascript library.
==Deployment & Dependency Management==
===Deployment & Dependency Management===
===Bundler===
====Bundler====
Rails 2 required specifying gems in the environment.rb files, in the config block associated with the
Rails 2 required specifying gems in the environment.rb files, in the config block associated with the
run method as:
run method as:
Line 317: Line 333:
installed to vendor/bundle and the Gemfile.lock must be checked in and up to date before bundler is
installed to vendor/bundle and the Gemfile.lock must be checked in and up to date before bundler is
run.
run.
==Performance==
===Performance===
Rails Application object:
Rails Application object:
As part of the groundwork for supporting running multiple Rails applications in the same process,
As part of the groundwork for supporting running multiple Rails applications in the same process,

Revision as of 02:21, 23 September 2011

Rails 2 and Rails 3

Introduction

Rails 3 has incorporated significant changes over its 2.x version improving on performance, modularity and elegant constructs and thereby reinforcing its principles Convention over configuration and DRY again. The internal architecture of the framework was refactored to make it more modular, flexible and coherent. Routing component has been revamped and it makes lot easier configure routes. Dependency management is also one of the significant improvements observed in 3.0. It is taken care by new Bundler component, which automates the process of installing, updating library management. The database operations are made much more efficient and closer to relational databases. There are many changes in Rails 3 from architectural to syntax changes and it’s too big to discuss all those in this article. However, this wiki article presents only major changes that are relevant to class and at same time illustrating those concepts with examples discussed in class, especially Cookbook Application in Rails 2. It is assumed that readers are familiar with Rails 2. With this, it serves as a quick tutorial to understand Rails 3 features.

Structural

Ruby Version

Rails 3.0 requires Ruby 1.8.7 or higher. Support for all of the previous Ruby versions has been dropped officially and you should upgrade as early as possible. Rails 3.0 is also compatible with Ruby 1.9.2.

Modularization

Versions prior to Rails 3 were strongly coupled to a limited choices of frameworks that formed the Rails stack. For example, a standard Rails stack used Active Record as its ORM layer, Action View for rendering its views, PrototypeJS as its javascript library and so on. However, with Rails 3, it has become more modular, starting with a rails-core, and including the ability to opt in or out of specific frameworks. Its default components, like ActiveRecord and ActionController, behave like regular plugins. This allows other plugins, like DataMapper, to use exactly the same APIs used by ActiveRecord and hence replace it if the end user desires..

Active Record

Change in query interface: In Rails 2, ActiveRecord provides the following finder methods :

  • find(id_or_array_of_ids, options)
  • find(:first, options)
  • find(:all, options)
  • first(options)
  • all(options)
  • update_all(updates, conditions, options)

And the following calculation methods :

  • count(column, options)
  • average(column, options)
  • minimum(column, options)
  • maximum(column, options)
  • sum(column, options)
  • calculate(operation, column, options)
  • Each of these methods take an options hash containing :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :having, :from & :lock. Starting with Rails 3, supplying any option has been deprecated (an exception here is that count() will still accept a :distinct option). Example of deprecated usage:
    User.find(:all, :limit => 1)
    User.find(:all)
    User.find(:first)
    User.first(:conditions => {:name => 'vaibhav'})
    User.all(:joins => :items)
    

    In Rails 3, Active Record, uses a framework – Arel, which has been taken on as the underpinnings of Active Record and is now required for Rails. Arel is a Relational Algebra for Ruby. It simplifies the generation complex of SQL queries and adapts to various RDBMS systems. Active Record, through the use of Arel, now returns relations on its core methods. ActiveRecord in Rails 3 will have the following new finder methods.

    • where (:conditions)
    • having (:conditions)
    • select
    • group
    • order
    • limit
    • offset
    • joins
    • includes (:include)
    • lock
    • readonly
    • from

    All of the above methods returns a Relation. All these methods are defined on the Relation object as well, making it possible to chain them.

    vaibhav = User.where(:name => 'vaibhav')
    new_users = User.order('users.id DESC').limit(20).includes(:items)
    

    The relation returned also supports the following methods: You could call any of the following methods on a relation :

    • new(attributes)
    • create(attributes)
    • create!(attributes)
    • find(id_or_array)
    • destroy(id_or_array)
    • destroy_all
    • delete(id_or_array)
    • delete_all
    • update(ids, updates)
    • update_all(updates)
    • exists?

    For example, in cookbook application In rails 2 for fetching all categories which have pizza we execute statement

    Category.find(:all, :conditions => {:recipe =>’pizza’})
    

    Whereas in rails 3 we have a very simple query that achieves same result by

    Category.where(:recipe => ‘pizza’)
    

    Active Model Abstraction

    Active Model was extracted while decoupling Rails’ historic connection between ActiveRecord, its default ORM, and ActionPack, its controller and view layer. All new ORM plugins (e.g. DataMapper or Sequel) now just need to implement Active Model interfaces to work seamlessly with Action Pack. The Active Model API itself is fairly small, with a few methods around validation, the ability to determine whether an object has persisted or not (which can be safely stubbed by objects without persistence), and a number of methods that tell ActionPack how to convert the object into a canonical URL or template name. By doing this, Rails has completely decoupled ActionPack from ActiveRecord directly, and ActiveRecord becomes just one of many ORMs to implement the ActiveModel API. An example is the use of validations (traditionally an Active Record feature) in any Ruby object that adheres to the Active Model API.

    class Person < ActiveRecord::Base
    validates_presence_of :first_name, :last_name
    end
    

    To do the same thing for a plain old Ruby object, simply do the following:

    class Person
    include ActiveModel::Validations
    validates_presence_of :first_name, :last_name
    attr_accessor :first_name, :last_name
    def initialize(first_name, last_name)
    @first_name, @last_name = first_name, last_name
    end
    end
    

    For example, In Cookbook application discussed in class we have the recipe model class with validations (Rails 2.x code)

    class Recipe < ActiveRecord::Base
    belongs_to :category
    validates :title, :presence => true
    validates :instructions, :presence => true
    validates :category, :presence => true
    end
    

    In Rails 3 we achive the same functionality by less code and has validates_presence_of method

    class Recipe
    include ActiveModel::Validations
    belongs_to :category
    validates_presence_of :title, :instructions, :category
    end
    

    Some other modules available in Active Model include:

    • AttributeMethods: Makes it easy to add attributes that are set like table_name :foo
    • Callbacks: ActiveRecord-style lifecycle callbacks.
    • Naming: Default implementations of model.model_name, which are used by ActionPack (for instance, when you do render :partial => model
    • Observing: ActiveRecord-style observers

    Action Controller

    Previously, ActionController had a number of disparate elements all in one place. This monolithic component is now divided into multiple pieces. Two significant componets are:

    ActionDispatch

    The dispatcher functionality has been moved into ActionDispatch, with the code inside tightened up and really made a conceptual component. This has resulted in a new routing API. While the old map.connect DSL still works just fine, the new standard DSL is less verbose and more readable. old way

    ActionController::Routing::Routes.draw do |map|
    map.connect "/main/:id", :controller => "main", :action => "home"
    end
    

    new way

    Piazza::Application.routes do
    match "/main/:id", :to => "main#home"
    end
    

    First, the routes are attached to the application, which is now its own object. Second, map is no longer required, and the new DSL (match/to) is more expressive. Finally, we have a shortcut for controller/ action pairs

    ("main#home" is {:controller => "main", :action => "home")
    

    Another useful shortcut allows you to specify the method more simply than before:

    Piazza::Application.routes do
    post "/main/:id", :to => "main#home", :as => :homepage
    end
    

    The :as in the above example specifies a named route, and creates the homepage_url et al helpers as in Rails 2.

    Simple routes Rails 2

    map.resources :posts,:member={:confirm=>:post,:notify=>:post} do |post|
    post.resources :comments,:member=>{:preview=>:post},:collection=>{:archived=>:get}
    end
    <\pre>
    Rails 3
    <pre>
    Resources :posts do
    member do
    post :confirm
    get :notify
    end
    Resources :comments do
    post :preview, <img src="http://vaibhav.com/images/smilies/icon_surprised.gif">
    n=>:member
    get :archived, <img src="http://harsha.com/images/smilies/icon_surprised.gif"">
    n=>:collection
    end
    end
    

    Root mapping Rails 2

    map.root :controller=>”user”
    

    Rails 3

    root :to=>”user#index”
    

    Legacy Route Rails 2

    Map.connect ':controller/:action/:id'
    Map.connect ':controller/:action/:id.:format'
    

    Rails 3

    Match ':controller(/:action(/:id(/:format)))
    

    AbstractController

    Rails 3 has refactored ActionController and ActionMailer to inherit from a common superclass: AbstractController. AbstractController includes the basic concept of controllers, rendering, layouts, helpers, and callbacks, but nothing about HTTP or mail delivery. ActionController now has AbstractController, a base superclass that is separated from the notions of HTTP. This AbstractController handles the basic notion of controllers, actions, and action dispatching, and not much else.

    Development

    Rails generator system

    The new script/rails replaces all the scripts that used to be in the script directory. You do not run script/ rails directly though, the rails command detects it is being invoked in the root of a Rails application and runs the script for you. Intended usage is:

    Rails 2 Rails 3
    rails script/generate rails g
    rails script/console rails c
    rails script/server rails s
    rails script/dbconsole rails db

    JS library support

    Rails 2 shipped with prototypejs as the default javascript library. However, Rails 3 makes it very easy to pick a javascript library of choice, for example you can now use jquery as the base javascript library.

    Deployment & Dependency Management

    Bundler

    Rails 2 required specifying gems in the environment.rb files, in the config block associated with the run method as:

    Rails::Initializer.run do |config|
    config.gem "aws-s3", :lib => "aws/s3"
    config.gem "fastercsv"
    config.gem "chargify_api_ares"
    config.gem "acts-as-taggable-on", :source => "http://gemcutter.org", :version => '2.0.0.rc1'
    end
    

    In contrast, Rails 3 uses a Gemfile in the application root to determine the gems you require for your application to start. This Gemfile is processed by the Bundler, which then installs all your dependencies. It takes a gem manifest file and is able to fetch, download, and install the gems and all child dependencies specified in this manifest. It can manage any update to the gem manifest file and update the bundle's gems accordingly. It also lets you run any ruby code in context of the bundle's gem environment. To use bundler, declare these dependencies in a file at the root of your application, called Gemfile. It looks something like this:

    source "http://rubygems.org"
    gem "aws-s3", "1.2.0"
    gem "fastercsv"
    gem "chargify_api_ares"
    gem "acts-as-taggable-on", "~> 1.4.2"
    

    Using this Gemfile, the bundler looks for gems declared in the Gemfile at http://rubygems.org. You can declare multiple Rubygems sources, and bundler will look for gems in the order you declared the sources. Next, the bundler goes through the list of dependencies declared:

    • version 1.2.0 of aws-s3
    • any version of fastercsv and chargify_api_ares<\li>
    • version of acts-as-taggable-on that is >= 1.4.2 but < 1.5.0<\li>

    After declaring the dependencies, you tell bundler to go get them:

    $ bundle install

    Bundler will connect to rubygems.org (and any other sources that you declared), and find a list of all of the required gems that meet the requirements you specified. Because all of the gems in your Gemfile have dependencies of their own (and some of those have their own dependencies), running bundle install on the Gemfile above will install quite a few gems. If any of the needed gems are already installed, Bundler will use them. After installing any needed gems to your system, bundler writes a snapshot of all of the gems and versions that it installed to Gemfile.lock. On production servers, you can enable deployment mode: $ bundle install --deployment The --deployment flag turns on defaults that are appropriate for a deployment environment. Gems are installed to vendor/bundle and the Gemfile.lock must be checked in and up to date before bundler is run.

    Performance

    Rails Application object: As part of the groundwork for supporting running multiple Rails applications in the same process, Rails 3 introduces the concept of an Application object. An application object holds all the application specific configurations and is very similar in nature to config/environment.rb from the previous versions of Rails. Each Rails application now must have a corresponding application object. The application object is defined in config/application.rb. If you’re upgrading an existing application to Rails 3, you must add this file and move the appropriate configurations from config/environment.rb to config/application.rb. Rails 3 has improved performance by reducing overhead in following areas

    • General Controller Overhead
    • Render Collections of Partials

    Here is a comparison graph of performance between Rail 2.3 vs Rails 3.0 in the above mentioned areas.

    References

    1. Rails 3 release notes: http://edgeguides.rubyonrails.org/3_0_release_notes.html
    2. Yehuda Katz's posts on the merge of Rails and Merb: http://www.engineyard.com/blog/2009/rails-and-merb-merge-the-anniversary-part-1-of-6/.
    3. Nick Kallen's posts on AREL: http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/
    4. Bundler: http://gembundler.com/
    5. Pratik Naik's post on the changes in Active Record: http://m.onkey.org/active-record-query-interface
    6. Cookbook Application on Rails 2 discussed in class.