现在的位置: 首页 > 综合 > 正文

Rails3教程系列之六:从Rails2到Rails3

2018年04月19日 ⁄ 综合 ⁄ 共 11194字 ⁄ 字号 评论关闭

趁着上班前写一段 @@

那么从前面的教程中我们学习了如何创建一个简单的博客应用, 我个人觉得无论你是新手还是从rails2过来, rails3还是比较容易上手的, 现在我们就来看下rails3相比rails2, 进步在哪里, 优势又在什么地方. (本来这章打算写ujs的, 无奈工作繁忙只能推到周日了)

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 

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 

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

3. 路由

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

在 rails2 中:

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

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

Ruby代码 复制代码
收藏代码
  1. resources :posts
    do 
  2.     resources :comments 
  3. end 

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

Ruby代码 复制代码
收藏代码
  1. post.resources :comments
  2.                  :member => {
    :preview => :post }, 
  3.                  :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 

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

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

对于基本路由, rails2:

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

那么在rails3中:

Ruby代码 复制代码
收藏代码
  1. match 'login' =>
    'session#new' 

对于具名路由, rails2:

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

在rails3中:

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

对于程序根路由, rails2:

Java代码 复制代码
收藏代码
  1. map.root :controller => 'users', :action =>
    'index' 

rails3:

Ruby代码 复制代码
收藏代码
  1. root :to => 'users#index' 

对于遗留路由, rails2:

Ruby代码 复制代码
收藏代码
  1. map.connect ':controller/:action/:id' 
  2. map.connect ':controller/:action/:id.:format' 

那么在rails3中写法更优雅:

Ruby代码 复制代码
收藏代码
  1. match ':controller(/:action(/:id(.:format)))' 

对于路由参数, rals2:

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

rails3:

Ruby代码 复制代码
收藏代码
  1. 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' 

在rails3中:

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

指定请求方式, rails2:

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

在rails3中:

Ruby代码 复制代码
收藏代码
  1. match '/articles/:year' =>
    "posts#index", :via =>
    :get 
  2. #或者更简单的: 
  3. 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/'

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

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

在rails3中:

Ruby代码 复制代码
收藏代码
  1. 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 

对于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 

4. Bundler与ActionController

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

Ruby代码 复制代码
收藏代码
  1. config.gem "haml" 
  2. 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' 

然后运行 $ 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. ... 

改进的语法:

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

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 
Ruby代码 复制代码
收藏代码
  1. 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 
Ruby代码 复制代码
收藏代码
  1. 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  

6. ActiveRelation 以及 ActiveModel

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

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

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

而在rails3中:

Ruby代码 复制代码
收藏代码
  1. @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 

对于命名范围, 在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 

而在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 

对于查找方法, rails2:

Ruby代码 复制代码
收藏代码
  1. Post.find(:all, :conditions => {:author =>
    "Joe"}, :includes =>
    :comments, :order =>
    "title", :limit => 10) 

在rails3:

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

7. 跨站点脚本(XSS)

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

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

抱歉!评论已关闭.