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

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
 
(17 intermediate revisions by the same user not shown)
Line 2: Line 2:


Rails 3 has incorporated significant changes over its 2.x version improving on performance, modularity
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 ''Don't repeat yourself (DRY)''
and elegant constructs thereby reinforcing its principles ''Convention over configuration'' and ''Don't repeat yourself (DRY)''
again. The internal architecture of the framework was refactored to make it more modular, flexible
again. The internal architecture of the framework is refactored to make it more modular, flexible
and coherent. Routing component has been revamped and it makes lot easier configure routes.
and coherent. Routing component has been revamped and it makes lot easier to configure routes.
Dependency management is also one of the significant improvements observed in 3.0. It is taken care
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.
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.
The database operations are made much more efficient and closer to relational databases.


===Introduction===
Rails 3 has undergone many changes from architectural to syntax and it’s too big to discuss all
 
those in a single article. However, this wiki article presents only major changes that are relevant to class
 
and at same time illustrating these concepts with examples discussed in class, especially Cookbook
Rails 3 has undergone many changes 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
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===
 
The structural changes relate to changes architecture. Many of the previously existing components have been realigned to make it better [http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller MVC] framework. The following sections talk about changes in all the three components namely, [http://expertiza.csc.ncsu.edu/wiki/index.php/CSC/ECE_517_Fall_2011/ch2_2f_vh#Active_Record Action Record], [http://expertiza.csc.ncsu.edu/wiki/index.php/CSC/ECE_517_Fall_2011/ch2_2f_vh#Action_Controller Action Controller] and also other supporting components.


====Ruby Version====
====Ruby Version====
Line 25: Line 22:
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 [http://en.wikipedia.org/wiki/Object-relational_mapping ORM] layer, Action View for
Rails stack. For example, a standard Rails stack used Active Record as its [http://en.wikipedia.org/wiki/Object-relational_mapping ORM] layer, Action View for
rendering its views, [http://en.wikipedia.org/wiki/Prototype_JavaScript_Framework PrototypeJS] as its javascript library and so on.
rendering its views, [http://en.wikipedia.org/wiki/Prototype_JavaScript_Framework 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
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,
to opt in or out of specific frameworks. Its default components, like [http://expertiza.csc.ncsu.edu/wiki/index.php/CSC/ECE_517_Fall_2011/ch2_2f_vh#Active_Record Active Record] and [http://expertiza.csc.ncsu.edu/wiki/index.php/CSC/ECE_517_Fall_2011/ch2_2f_vh#Action_Controller Action Controller],
behave like regular plugins. This allows other plugins, like [http://en.wikipedia.org/wiki/Datamapper DataMapper], to use exactly the same APIs
behave like regular plugins. This allows other plugins, like [http://en.wikipedia.org/wiki/Datamapper 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.
Line 134: Line 129:


====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 Active Record, its
default ORM, and [http://ap.rubyonrails.org/ ActionPack], its controller and view layer. All new ORM plugins (e.g. DataMapper or
default ORM, and [http://ap.rubyonrails.org/ Action Pack], 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
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
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),
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
and a number of methods that tell Action Pack how to convert the object into a canonical URL or
template name. By doing this, Rails has completely decoupled ActionPack from ActiveRecord directly,
template name. By doing this, Rails has completely decoupled Action Pack from Active Record directly,
and ActiveRecord becomes just one of many ORMs to implement the ActiveModel API. An example
and Active Record becomes just one of many ORMs to implement the Active Model API. An example
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.
Line 196: Line 191:


====Action Controller====
====Action Controller====
Previously, ActionController had a number of disparate elements all in one place. This monolithic
Previously, Action Controller 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=====
=====Action Dispatch=====
The dispatcher functionality has been moved into ActionDispatch, with the code inside tightened
The dispatcher functionality has been moved into Action Dispatch, 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
map.connect DSL still works just fine, the new standard DSL is less verbose and more readable.
map.connect [http://en.wikipedia.org/wiki/Domain-specific_language DSL] still works just fine, the new standard DSL is less verbose and more readable.


Rails 2
Rails 2
Line 277: Line 272:
</pre>
</pre>


====AbstractController====
====Abstract Controller====
Rails 3 has refactored ActionController and ActionMailer to inherit from a common superclass:
Rails 3 has refactored Action Controller and Action Mailer 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,
helpers, and callbacks, but nothing about HTTP or mail delivery.
helpers, and callbacks, but nothing about [http://en.wikipedia.org/wiki/HTTP HTTP] or mail delivery.
ActionController now has AbstractController, a base superclass that is separated from the notions of
[http://expertiza.csc.ncsu.edu/wiki/index.php/CSC/ECE_517_Fall_2011/ch2_2f_vh#Action_Controller Action Controller] now has Abstract Controller, a base superclass that is separated from the notions of
[http://en.wikipedia.org/wiki/HTTP HTTP]. This AbstractController handles the basic notion of controllers, actions, and action dispatching,
HTTP. This Abstract Controller handles the basic notion of controllers, actions, and action dispatching,
and not much else.
and not much else.


===Development===
===Development===
This section presents changes related to code generation commands like scaffold and migration commands. Many of the commands in Rails 2 have aliases in Rails 3 which are easy to remember and hence helps in reducing development phase cycle.
====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/
Line 311: Line 308:
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====

Latest revision as of 04:44, 30 September 2011

Rails 2 and Rails 3

Rails 3 has incorporated significant changes over its 2.x version improving on performance, modularity and elegant constructs thereby reinforcing its principles Convention over configuration and Don't repeat yourself (DRY) again. The internal architecture of the framework is refactored to make it more modular, flexible and coherent. Routing component has been revamped and it makes lot easier to 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.

Rails 3 has undergone many changes from architectural to syntax and it’s too big to discuss all those in a single article. However, this wiki article presents only major changes that are relevant to class and at same time illustrating these 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

The structural changes relate to changes architecture. Many of the previously existing components have been realigned to make it better MVC framework. The following sections talk about changes in all the three components namely, Action Record, Action Controller and also other supporting components.

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 Active Record and Action Controller, 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 Active Record, its default ORM, and Action Pack, 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 Action Pack how to convert the object into a canonical URL or template name. By doing this, Rails has completely decoupled Action Pack from Active Record directly, and Active Record becomes just one of many ORMs to implement the Active Model 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, Action Controller had a number of disparate elements all in one place. This monolithic component is now divided into multiple pieces. Two significant componets are:

    Action Dispatch

    The dispatcher functionality has been moved into Action Dispatch, 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.

    Rails 2

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

    Rails 3

    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
    

    Rails 3

    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)))
    

    Abstract Controller

    Rails 3 has refactored Action Controller and Action Mailer 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. Action Controller now has Abstract Controller, a base superclass that is separated from the notions of HTTP. This Abstract Controller handles the basic notion of controllers, actions, and action dispatching, and not much else.

    Development

    This section presents changes related to code generation commands like scaffold and migration commands. Many of the commands in Rails 2 have aliases in Rails 3 which are easy to remember and hence helps in reducing development phase cycle.

    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.

    Alt text
    For basic operations the graph shows basic statements execution time vs Rails version
    Alt text
    For complex operations the graph shows complex statements execution time vs Rails version

    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.