CSC/ECE 517 Fall 2011/ch2 2f vh: Difference between revisions
No edit summary |
|||
(30 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 elegant constructs thereby reinforcing its principles ''Convention over configuration'' and ''Don't repeat yourself (DRY)'' | ||
again. The internal architecture of the framework | 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. | ||
Rails 3 has undergone many changes from architectural to syntax and it’s too big to discuss all | |||
Rails 3 has undergone many changes from architectural to syntax | those in a single article. However, this wiki article presents only major changes that are relevant to class | ||
those in | and at same time illustrating these concepts with examples discussed in class, especially Cookbook | ||
and at same time illustrating | |||
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==== | ||
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 [http://en.wikipedia.org/wiki/Object-relational_mapping ORM] layer, Action View for | ||
rendering its views, 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 | 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 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. | ||
====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 : | ||
<ul> | <ul> | ||
Line 40: | Line 44: | ||
<li>update_all(updates, conditions, options)</li> | <li>update_all(updates, conditions, options)</li> | ||
</ul> | </ul> | ||
And the following calculation methods : | And the following calculation methods : | ||
<ul> | <ul> | ||
<li>count(column, options)</li> | <li>count(column, options)</li> | ||
Line 48: | Line 54: | ||
<li>sum(column, options)</li> | <li>sum(column, options)</li> | ||
<li>calculate(operation, column, options)</li> | <li>calculate(operation, column, options)</li> | ||
Each of these methods take an options hash | Each of these methods take an options hash | ||
containing :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :having, :from | containing :conditions, :include, :joins, :limit, :offset, :order, :select, :readonly, :group, :having, :from | ||
Line 53: | Line 60: | ||
Starting with Rails 3, supplying any option has been deprecated (an exception here is that count() will | Starting with Rails 3, supplying any option has been deprecated (an exception here is that count() will | ||
still accept a :distinct option). | still accept a :distinct option). | ||
Example of deprecated usage: | Example of deprecated usage: | ||
<pre> | <pre> | ||
User.find(:all, :limit => 1) | User.find(:all, :limit => 1) | ||
Line 61: | Line 70: | ||
User.all(:joins => :items) | User.all(:joins => :items) | ||
</pre> | </pre> | ||
In Rails 3, Active Record, uses a framework – Arel, which has been taken on as the underpinnings | 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 | of Active Record and is now required for Rails. Arel is a [http://en.wikipedia.org/wiki/Relational_algebra Relational Algebra] for Ruby. It simplifies the | ||
generation complex of SQL queries and adapts to various RDBMS systems. Active Record, through | generation complex of [http://en.wikipedia.org/wiki/SQL SQL] queries and adapts to various [http://en.wikipedia.org/wiki/RDBMS RDBMS] systems. Active Record, through | ||
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. | ||
Line 119: | Line 129: | ||
====Active Model Abstraction==== | ====Active Model Abstraction==== | ||
Active Model was extracted while decoupling Rails’ historic connection between | Active Model was extracted while decoupling Rails’ historic connection between Active Record, its | ||
default ORM, and | 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 | 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 | template name. By doing this, Rails has completely decoupled Action Pack from Active Record directly, | ||
and | 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 179: | Line 189: | ||
<li>Observing: ActiveRecord-style observers</li> | <li>Observing: ActiveRecord-style observers</li> | ||
</ul> | </ul> | ||
====Action Controller==== | ====Action Controller==== | ||
Previously, | 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: | ||
===== | =====Action Dispatch===== | ||
The dispatcher functionality has been moved into | 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 261: | Line 272: | ||
</pre> | </pre> | ||
==== | ====Abstract Controller==== | ||
Rails 3 has refactored | 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. | ||
[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. This | 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 294: | 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==== | ||
Line 360: | Line 375: | ||
areas. | areas. | ||
{| | {| | ||
|[[File:Blog 19small-1-.jpg|alt=Alt text|400px|center|thumb|For basic operations]] | |[[File:Blog 19small-1-.jpg|alt=Alt text|400px|center|thumb|For basic operations the graph shows basic statements execution time vs Rails version]] | ||
|[[File:Blog 19big-1-.jpg|alt=Alt text|400px|center|thumb|For complex operations]] | |[[File:Blog 19big-1-.jpg|alt=Alt text|400px|center|thumb|For complex operations the graph shows complex statements execution time vs Rails version]] | ||
|} | |} | ||
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.
References
- Rails 3 release notes: http://edgeguides.rubyonrails.org/3_0_release_notes.html
- 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/.
- Nick Kallen's posts on AREL: http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/
- Bundler: http://gembundler.com/
- Pratik Naik's post on the changes in Active Record: http://m.onkey.org/active-record-query-interface
- Cookbook Application on Rails 2 discussed in class.