Rails版本区别

本文详细介绍了Rails 2到Rails 3的迁移过程,包括脚本命令的变更、配置文件的更新、路由规则的简化、ActionMailer的改进、ActiveRecord查询的优化以及跨站脚本防护的加强等核心变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 脚本命令

旧的命令                                      新的用法

script/generate                          rails g

script/console                            rails c

script/server                              rails s

script/dbconsole                        rails db

 

 

2. 配置文件

rails2: config/environment.rb

 

Ruby代码
  1. Rails::Initializer.run  do  |config|  
  2.     config.load_paths += %W( #{RAILS_ROOT}/extras )   
  3.     config.gem "bj"   
  4.     config.gem "sqlite3-ruby":lib  =>  "sqlite3"   
  5.     config.gem "aws-s3":lib  =>  "aws/s3"   
  6.     config.plugins = [ :exception_notification  ]  
  7.     config.time_zone = 'UTC'   
  8. end   
Rails::Initializer.run do |config|
    config.load_paths += %W( #{RAILS_ROOT}/extras )
    config.gem "bj"
    config.gem "sqlite3-ruby", :lib => "sqlite3"
    config.gem "aws-s3", :lib => "aws/s3"
    config.plugins = [ :exception_notification ]
    config.time_zone = 'UTC'
end

 

 

rails3:config/application.rb

 

Ruby代码
  1. module  APP_NAME  
  2.     class  Application < Rails::Application  
  3.         config.load_paths += %W( #{RAILS_ROOT}/extras )   
  4.         config.plugins = [ :exception_notification  ]  
  5.         config.time_zone = 'UTC'   
  6.     end   
  7. end   
module APP_NAME
    class Application < Rails::Application
        config.load_paths += %W( #{RAILS_ROOT}/extras )
        config.plugins = [ :exception_notification ]
        config.time_zone = 'UTC'
    end
end

 

 这样就变成了一种架构式的应用, 我们可以根据方便的对config进行操作

 

3. 路由

在rails3中, 已经的路由可以继续工作, 而新的路由方式更加简洁.

在 rails2 中:

 

Ruby代码
  1. map.resources  :posts   do  |post|  
  2.     post.resources :comments   
  3. end   
map.resources :posts do |post|
    post.resources :comments
end

而在rails3中 , 表达更为形象:

 

Ruby代码
  1. resources  :posts   do   
  2.     resources :comments   
  3. end   
resources :posts do
    resources :comments
end

 

对于一些复杂的路由, rails2:

 

Ruby代码
  1. post.resources  :comments ,  
  2.                  :member  => {  :preview  =>  :post  },  
  3.                  :collection  => {  :archived  =>  :get  }  
post.resources :comments,
                 :member => { :preview => :post },
                 :collection => { :archived => :get }

rails3中可以这样表达:

 

Ruby代码
  1. resources  :comments   do   
  2.     member do   
  3.         post :preview   
  4.     end   
  5.     collection do   
  6.         get :archived   
  7.     end   
  8. end   
resources :comments do
    member do
        post :preview
    end
    collection do
        get :archived
    end
end

 不够简洁? 我们还可以这样做:

 

Ruby代码
  1. resources  :comments   do   
  2.     post :preview:on  =>  :member   
  3.     get :archived:on  =>  :collection   
  4. end   
resources :comments do
    post :preview, :on => :member
    get :archived, :on => :collection
end

 

对于基本路由, rails2:

 

Ruby代码
  1. map.connect  'login':controller  =>  'session':action  =>  'new'   
map.connect 'login', :controller => 'session', :action => 'new'

 那么在rails3中:


Ruby代码
  1. match  'login'  =>  'session#new'   
match 'login' => 'session#new'


对于具名路由, rails2:


Ruby代码
  1. map.login  'login':controller  =>  'session':action  =>  'new'   
map.login 'login', :controller => 'session', :action => 'new'

在rails3中:

 

Ruby代码
  1. match  'login'  =>  'session#new':as  =>  :login   
match 'login' => 'session#new', :as => :login

 

对于程序根路由, rails2:

 

ruby代码
  1. map.root :controller =>  'users' , :action =>  'index'   
map.root :controller => 'users', :action => 'index'

 rails3:

 

Ruby代码
  1. root  :to  =>  'users#index'   
root :to => 'users#index'

 

对于遗留路由, rails2:

 

Ruby代码
  1. map.connect  ':controller/:action/:id'   
  2. map.connect ':controller/:action/:id.:format'   
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'

 那么在rails3中写法更优雅:


Ruby代码
  1. match  ':controller(/:action(/:id(.:format)))'   
match ':controller(/:action(/:id(.:format)))'

 

对于路由参数, rals2:

 

Ruby代码
  1. map.connect  '/articles/:year/:month/:day':controller  =>  'posts':action  =>  'index'   
map.connect '/articles/:year/:month/:day', :controller => 'posts', :action => 'index'

 rails3:

 

Ruby代码
  1. match  '/articles/:year/:month/:day'  =>  "posts#index"   
match '/articles/:year/:month/:day' => "posts#index"

 

那么对于存档请求, 比如rails2:

 

Ruby代码
  1. map.connect  '/articles/:year/:month/:day':controller  =>  'posts':action  =>  'index'   
  2. map.connect '/articles/:year/:month':controller  =>  'posts':action  =>  'index'   
  3. map.connect '/articles/:year':controller  =>  'posts':action  =>  'index'   
map.connect '/articles/:year/:month/:day', :controller => 'posts', :action => 'index'
map.connect '/articles/:year/:month', :controller => 'posts', :action => 'index'
map.connect '/articles/:year', :controller => 'posts', :action => 'index'

 在rails3中:

 

Ruby代码
  1. match  '/articles(/:year(/:month(/:day)))'  =>  "posts#index"   
match '/articles(/:year(/:month(/:day)))' => "posts#index"

 

指定请求方式, rails2:

 

Ruby代码
  1. map.connect  '/articles/:year':controller  =>  'posts':action  =>  'index' ,  
  2. :conditions  => { :method  =>  :get }  
map.connect '/articles/:year', :controller => 'posts', :action => 'index',
:conditions => {:method => :get}

 在rails3中:

 

Ruby代码
  1. match  '/articles/:year'  =>  "posts#index":via  =>  :get   
  2. #或者更简单的:   
  3. get '/articles/:year'  =>  "posts#index"   
match '/articles/:year' => "posts#index", :via => :get
#或者更简单的:
get '/articles/:year' => "posts#index"


对于跳转, rails3:

 

Ruby代码
  1. match  'signin':to  => redirect( "/login" )  
  2. match 'users/:name':to  => redirect {|params|  "/#{params[:name]}"  }  
  3. match 'google'  => redirect( 'http://www.google.com/' )  
match 'signin', :to => redirect("/login")
match 'users/:name', :to => redirect {|params| "/#{params[:name]}" }
match 'google' => redirect('http://www.google.com/')

 

路由约束: rails2中实际上使用了 :requirements 符号

 

Ruby代码
  1. map.connect  '/:year':controller  =>  'posts':action  =>  'index' ,  
  2.                                     :requirements  => {  :year  => //d{4}/ }  
map.connect '/:year', :controller => 'posts', :action => 'index',
                                    :requirements => { :year => //d{4}/ }

 在rails3中:

 

Ruby代码
  1. match  '/:year'  =>  "posts#index":constraints  => { :year  => //d{4}/}  
match '/:year' => "posts#index", :constraints => {:year => //d{4}/}
Ruby代码
  1. :constraints  => {  :user_agent  => /iphone/ }  
  2. :constraints  => {  :ip  => /192/.168/.1/./d{1,3}/ }  
  3. constraints(:host  => /localhost/)  do   
  4.     resources :posts   
  5. end   
  6. constraints IpRestrictor do   
  7.     get 'admin/accounts'  =>  "queenbee#accounts"   
  8. end   
:constraints => { :user_agent => /iphone/ }
:constraints => { :ip => /192/.168/.1/./d{1,3}/ }
constraints(:host => /localhost/) do
    resources :posts
end
constraints IpRestrictor do
    get 'admin/accounts' => "queenbee#accounts"
end

 

对于Rack应用, rails3:

 

Ruby代码
  1. get  'hello'  => proc { |env| [200, {},  "Hello Rack" ] }  
  2.   
  3. get 'rack_endpoint'  => PostsController.action( :index )  
  4.   
  5. get 'rack_app'  => CustomRackApp  
get 'hello' => proc { |env| [200, {}, "Hello Rack"] }

get 'rack_endpoint' => PostsController.action(:index)

get 'rack_app' => CustomRackApp
 

4. Bundler与ActionController

一个典型的rails应用, 我们一般需要在 environment.rb 指定你的 gems:

 

Ruby代码
  1. config.gem  "haml"   
  2. config.gem "chronic":version  =>  '0.2.3'   
config.gem "haml"
config.gem "chronic", :version => '0.2.3'

 然后我们运行 $ rake gems:install, 该命令会取得并下载然后安装编译这些gems到你的系统RubyGems目录中.

之后我们运行 $ rake gems:unpack:dependencise, 把这些gem打包到你应用程序的vendor/gems目录中去.

 

这样做产生的问题:

1. 它直接绑定到Rails中

2. 没有从本质上解决依赖问题

3. 运行时容易发生冲突

 

在rails3中, 使用了 bundle 命令:

直接在你的 gemfile 中指定你的 gem

 

Ruby代码
  1. gem  "haml"   
  2. gem "chronic"'0.2.3'   
gem "haml"
gem "chronic", '0.2.3'

 然后运行 $ bundle, 该命令会会取得并下载然后安装编译这些gems

然后运行 $ bundle package 把gem源移到/vendor/cache中去.

 

这样rails应用中的gem与系统中的gem就不会相冲突.

 

 

一般的控制器语法:

 

Ruby代码
  1. class  UsersController < ApplicationController  
  2.     def  index  
  3.         @users  = User.all  
  4.         respond_to do  |format|  
  5.             format.html  
  6.             format.xml { render :xml  =>  @users .to_xml }   
  7.         end   
  8.     end   
  9.   
  10.     def  show  
  11.         @user  = User.find(params[ :id ])  
  12.         respond_to do  |format|  
  13.             format.html # show.html.erb   
  14.             format.xml { render :xml  =>  @user  }  
  15.         end   
  16.     end   
  17.   
  18. ...  
class UsersController < ApplicationController
    def index
        @users = User.all
        respond_to do |format|
            format.html
            format.xml { render :xml => @users.to_xml } 
        end
    end

    def show
        @user = User.find(params[:id])
        respond_to do |format|
            format.html # show.html.erb
            format.xml { render :xml => @user }
        end
    end

...

 

改进的语法:

 

Ruby代码
  1. class  UsersController < ApplicationController  
  2.     respond_to :html:xml:json   
  3.     def  index  
  4.         @users  = User.all  
  5.         respond_with(@users )  
  6.     end   
  7.     def  show  
  8.         @user  = User.find(params[ :id ])  
  9.         respond_with(@user )  
  10.     end   
  11. ...  
class UsersController < ApplicationController
    respond_to :html, :xml, :json
    def index
        @users = User.all
        respond_with(@users)
    end
    def show
        @user = User.find(params[:id])
        respond_with(@user)
    end
...



 

 

5. ActionMailer

rails2:  $ script/generate mailer UserMailer welcome forgot_password

这将创建 app/models/user_mailer.rb

那么在rails3中: $ rails g mailer UserMailer welcome forgot_password

这将创建 app/mailers /user_mailer.rb


在实现部分, rails2:

 

Ruby代码
  1. def  welcome(user, subdomain)  
  2.     subject 'Welcome to TestApp'   
  3.     recipients user.email  
  4.     from 'admin@testapp.com'   
  5.     body :user  => user,  :subdomain  => subdomain  
  6. end   
def welcome(user, subdomain)
    subject 'Welcome to TestApp'
    recipients user.email
    from 'admin@testapp.com'
    body :user => user, :subdomain => subdomain
end
Ruby代码
  1. UserMailer.deliver_welcome(user, subdomain)   
UserMailer.deliver_welcome(user, subdomain) 

在rails3中:

Ruby代码
  1. def  welcome(user, subdomain)  
  2.     @user  = user  
  3.     @subdomain  = subdomain  
  4.     mail(:from  =>  "admin@testapp.com" ,  
  5.             :to  => user.email,  
  6.             :subject  =>  "Welcome to TestApp" )  
  7. end   
def welcome(user, subdomain)
    @user = user
    @subdomain = subdomain
    mail(:from => "admin@testapp.com",
            :to => user.email,
            :subject => "Welcome to TestApp")
end
Ruby代码
  1. UserMailer.welcome(user, subdomain).deliver  
UserMailer.welcome(user, subdomain).deliver

 

相比rails2, 我们在rails3下实现一个mail要简单的多:

Ruby代码
  1. class  UserMailer < ActionMailer::Base  
  2.     default :from  =>  "admin@testapp.com" ,  
  3.                 :reply_to  =>  "noreply@testapp.com" ,  
  4.                 "X-Time-Code"  =>  Time .now.to_i.to_s  
  5.     def  welcome(user, subdomain)  
  6.         @user  = user  
  7.         @subdomain  = subdomain  
  8.         attachments['test.pdf' ] =  File .read( "#{Rails.root}/public/test.pdf" )  
  9.         mail(:to  =>  @user .email,  :subject  =>  "Welcome to TestApp"do  |format|  
  10.             format.html { render 'other_html_welcome'  }  
  11.             format.text { render 'other_text_welcome'  }  
  12.         end   
  13.     end   
  14. end    
class UserMailer < ActionMailer::Base
    default :from => "admin@testapp.com",
                :reply_to => "noreply@testapp.com",
                "X-Time-Code" => Time.now.to_i.to_s
    def welcome(user, subdomain)
        @user = user
        @subdomain = subdomain
        attachments['test.pdf'] = File.read("#{Rails.root}/public/test.pdf")
        mail(:to => @user.email, :subject => "Welcome to TestApp") do |format|
            format.html { render 'other_html_welcome' }
            format.text { render 'other_text_welcome' }
        end
    end
end 

 

 

6. ActiveRelation 以及 ActiveModel


在rails2中, 我们经常使用下面的方法来进行查询:

Ruby代码
  1. @posts  = Post.find( :all:conditions  => { :published  =>  true })  
@posts = Post.find(:all, :conditions => {:published => true})

       该方式将立即查询数据库然后返回Posts数组

 

而在rails3中:

Ruby代码
  1. @posts  = Post.where( :published  =>  true )  
@posts = Post.where(:published => true)

      该方法不会查询数据库, 仅仅返回一个 ActiveRecord::Relation 对象, 然后:

 

Ruby代码
  1. @posts  = Post.where( :published  =>  true )  
  2. if  params[ :order ]  
  3.     @posts  =  @posts .order(params[ :order ])  
  4. end   
  5. @posts . each   do  |p|  
  6.     ...                 #在这里进行查询, 实现延迟加载   
  7. end   
@posts = Post.where(:published => true)
if params[:order]
    @posts = @posts.order(params[:order])
end
@posts.each do |p|
    ...                 #在这里进行查询, 实现延迟加载
end

 

对于命名范围, 在rails2中:

 

Ruby代码
  1. class  Post < ActiveRecord::Base  
  2.     default_scope :order  =>  'title'   
  3.     named_scope :published:conditions  => { :published  =>  true }  
  4.     named_scope :unpublished:conditions  => { :published  =>  false }  
  5. end   
class Post < ActiveRecord::Base
    default_scope :order => 'title'
    named_scope :published, :conditions => {:published => true}
    named_scope :unpublished, :conditions => {:published => false}
end

而在rails3中:


Ruby代码
  1. class  Post < ActiveRecord::Base  
  2.     default_scope order('title' )  
  3.     scope :published , where( :published  =>  true )  
  4.     scope :unpublished , where( :published  =>  false )  
  5. end   
class Post < ActiveRecord::Base
    default_scope order('title')
    scope :published, where(:published => true)
    scope :unpublished, where(:published => false)
end

 

对于查找方法, rails2:

 

Ruby代码
  1. Post.find( :all:conditions  => { :author  =>  "Joe" },  :includes  =>  :comments:order  =>  "title":limit  => 10) 
  2.                                                                                                                                                                                   在rails3:
Post.find(:all, :conditions => {:author => "Joe"}, :includes => :comments, :order => "title", :limit => 10)


Ruby代码
  1. Post.where( :author  =>  "Joe" ).include( :comments ).order( :title ).limit(10).<strong><span style= "font-size: medium;" >all</span></strong>  
Post.where(:author => "Joe").include(:comments).order(:title).limit(10).all



 

 

7. 跨站点脚本(XSS)

在rails2中, 一般我们输入一段文本的时候, 我们往往会这样写: <%= h @post.body %>

那么在rails3中, <%= @post.body %> 默认输出的是一段safe html, 如果想输出XSS, 可以在前面加上 raw

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值