1 升級至 Rails 3.2
如果您正在升級現有應用程式,在開始之前,最好能有良好的測試涵蓋率。如果您尚未升級到 Rails 3.1,您也應該先升級到 Rails 3.1,並確保您的應用程式在嘗試更新到 Rails 3.2 之前,仍能如預期般執行。然後注意下列變更
1.1 Rails 3.2 至少需要 Ruby 1.8.7
Rails 3.2 需要 Ruby 1.8.7 或更高版本。對於所有先前 Ruby 版本的支援已正式終止,您應該盡快升級。Rails 3.2 也相容於 Ruby 1.9.2。
請注意,Ruby 1.8.7 p248 和 p249 有封送錯誤,會讓 Rails 崩潰。Ruby Enterprise Edition 已在 1.8.7-2010.02 發行後修正這些錯誤。在 1.9 方面,Ruby 1.9.1 無法使用,因為它會直接發生分段錯誤,因此如果您想要使用 1.9.x,請跳到 1.9.2 或 1.9.3,以順利執行。
1.2 在您的應用程式中要更新的內容
更新您的
Gemfile
,以相依於rails = 3.2.0
sass-rails ~> 3.2.3
coffee-rails ~> 3.2.1
uglifier >= 1.0.3
Rails 3.2 已將
vendor/plugins
標示為不建議使用,而 Rails 4.0 將會完全移除它們。您可以開始將這些外掛程式取代為 gem,並將它們新增到您的Gemfile
中。如果您選擇不將它們製作成 gem,您可以將它們移到,例如,lib/my_plugin/*
,並在config/initializers/my_plugin.rb
中新增適當的初始化程式。有幾個新的組態變更,您會想要將它們新增到
config/environments/development.rb
中# Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict # Log the query plan for queries taking more than this (works # with SQLite, MySQL, and PostgreSQL) config.active_record.auto_explain_threshold_in_seconds = 0.5
mass_assignment_sanitizer
組態也需要新增到config/environments/test.rb
中# Raise exception on mass assignment protection for Active Record models config.active_record.mass_assignment_sanitizer = :strict
1.3 在您的引擎中要更新的內容
將 script/rails
中註解底下的程式碼取代為下列內容
ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/your_engine_name/engine', __FILE__)
require "rails/all"
require "rails/engine/commands"
2 建立 Rails 3.2 應用程式
# You should have the 'rails' RubyGem installed
$ rails new myapp
$ cd myapp
2.1 供應寶石
Rails 現在在應用程式根目錄中使用 Gemfile
來決定你的應用程式啟動所需寶石。這個 Gemfile
由 Bundler 寶石處理,然後安裝你的所有相依性。它甚至可以將所有相依性安裝在你的應用程式本機,讓它不依賴系統寶石。
更多資訊:Bundler 首頁
2.2 站在最前線
Bundler
和 Gemfile
讓凍結你的 Rails 應用程式變得像吃派一樣容易,使用新的專用 bundle
指令。如果你想直接從 Git 儲存庫打包,你可以傳遞 --edge
旗標
$ rails new myapp --edge
如果你有 Rails 儲存庫的本機簽出,並想使用它產生應用程式,你可以傳遞 --dev
旗標
$ ruby /path/to/rails/railties/bin/rails new myapp --dev
3 個主要功能
3.1 更快的開發模式和路由
Rails 3.2 附帶一個開發模式,明顯地更快。受到 Active Reload 的啟發,Rails 僅在檔案實際變更時重新載入類別。在較大的應用程式上,效能提升非常顯著。路由辨識也因為新的 Journey 引擎而變得更快。
3.2 自動查詢說明
Rails 3.2 附帶一個不錯的功能,它會說明由 Arel 產生的查詢,方法是在 ActiveRecord::Relation
中定義一個 explain
方法。例如,你可以執行類似 puts Person.active.limit(5).explain
的動作,然後 Arel 產生的查詢就會被說明。這允許檢查適當的索引和進一步的最佳化。
執行時間超過半秒的查詢會在開發模式中自動說明。當然,這個閾值可以變更。
3.3 標籤記錄
當執行多使用者、多帳戶應用程式時,能夠依據執行者過濾日誌會很有幫助。Active Support 中的 TaggedLogging 可協助執行此動作,方法是為日誌列加上子網域、要求 ID,以及其他有助於偵錯此類應用程式的資訊。
4 文件
從 Rails 3.2 開始,Rails 指南可供 Kindle 和 iPad、iPhone、Mac、Android 等裝置使用的免費 Kindle 閱讀應用程式使用。
5 Railties
如果相依檔案已變更,則僅重新載入類別以加速開發。可以透過將
config.reload_classes_only_on_change
設為 false 來關閉此功能。新的應用程式會在環境設定檔中取得旗標
config.active_record.auto_explain_threshold_in_seconds
。在development.rb
中的值為0.5
,在production.rb
中則已註解。在test.rb
中未提及。新增
config.exceptions_app
,以設定當例外狀況發生時,由ShowException
中介軟體呼叫的例外狀況應用程式。預設為ActionDispatch::PublicExceptions.new(Rails.public_path)
。新增
DebugExceptions
中介軟體,其中包含從ShowExceptions
中介軟體萃取出的功能。在
rake routes
中顯示已掛載引擎的路由。允許使用
config.railties_order
變更 railties 的載入順序,例如config.railties_order = [Blog::Engine, :main_app, :all]
Scaffold 會傳回 204 無內容,以供沒有內容的 API 要求使用。這使得 scaffold 能夠直接與 jQuery 搭配使用。
更新
Rails::Rack::Logger
中介軟體,以將config.log_tags
中設定的任何標籤套用至ActiveSupport::TaggedLogging
。這使得為日誌列加上子網域和要求 ID 等偵錯資訊變得容易,這兩個資訊在偵錯多使用者製作應用程式時都很有幫助。可以在
~/.railsrc
中設定rails new
的預設選項。您可以在家目錄中的.railsrc
設定檔中指定每次執行rails new
時要使用的額外命令列引數。新增
d
別名,用於destroy
。這也適用於引擎。scaffold 和模型產生器的屬性預設為字串。這允許執行下列動作:
bin/rails g scaffold Post title body:text author
允許 scaffold/model/migration 產生器接受「index」和「uniq」修改詞。例如,
$ bin/rails g scaffold Post title:string:index author:uniq price:decimal{7,2}
將為
title
和author
建立索引,後者為唯一索引。某些類型(例如小數)接受自訂選項。在範例中,price
將會是小數欄位,精度和比例分別設定為 7 和 2。已從預設的
Gemfile
中移除 gem。移除舊的 plugin 產生器
rails generate plugin
,改用rails plugin new
指令。移除舊的
config.paths.app.controller
API,改用config.paths["app/controller"]
。
5.1 已棄用
Rails::Plugin
已棄用,且將在 Rails 4.0 中移除。請改用 gem 或 bundler 搭配路徑或 git 相依性,而非將 plugin 加入vendor/plugins
。
6 Action Mailer
已將
mail
版本升級至 2.4.0。已移除自 Rails 3.0 以來已棄用的舊 Action Mailer API。
7 Action Pack
7.1 Action Controller
將
ActiveSupport::Benchmarkable
設定為ActionController::Base
的預設模組,因此#benchmark
方法會再度於 controller 背景中提供,如同過去一般。已將
:gzip
選項加入caches_page
。預設選項可使用page_cache_compression
全域設定。當您使用
:only
和:except
條件指定版面,且這些條件失敗時,Rails 現在將使用您的預設版面(例如「layouts/application」)。class CarsController layout 'single_car', :only => :show end
當要求進入
:show
動作時,Rails 將使用layouts/single_car
;當要求進入任何其他動作時,Rails 將使用layouts/application
(或layouts/cars
,如果存在)。如果提供
:as
選項,form_for
已變更為使用#{action}_#{as}
作為 CSS 類別和 ID。較早的版本使用#{as}_#{action}
。Active Record 模型上的
ActionController::ParamsWrapper
現在僅封裝已設定的attr_accessible
屬性。如果未設定,則僅封裝類別方法attribute_names
傳回的屬性。這透過將巢狀屬性加入attr_accessible
來修正巢狀屬性的封裝。每次 before 回呼中斷時,都會記錄「Filter chain halted as CALLBACKNAME rendered or redirected」。
ActionDispatch::ShowExceptions
已重構。控制器負責選擇是否顯示例外。可以在控制器中覆寫show_detailed_exceptions?
以指定哪些要求應在錯誤中提供偵錯資訊。回應器現在會針對沒有回應主體的 API 要求傳回 204 無內容(如新的架構中)。
ActionController::TestCase
的 Cookie 已重構。現在應使用cookies[]
為測試案例指定 Cookie。cookies[:email] = '[email protected]' get :index assert_equal '[email protected]', cookies[:email]
若要清除 Cookie,請使用
clear
。cookies.clear get :index assert_nil cookies[:email]
我們現在不再寫出 HTTP_COOKIE,且 Cookie 儲存區在要求之間是持續的,因此,如果您需要為測試操作環境,您需要在建立 Cookie 儲存區之前進行操作。
如果未提供
:type
,send_file
現在會從檔案副檔名猜測 MIME 類型。已新增 PDF、ZIP 及其他格式的 MIME 類型項目。
允許
fresh_when/stale?
使用記錄,而非選項雜湊。將遺失 CSRF 令牌的警告記錄層級從
:debug
變更為:warn
。資產預設應使用要求通訊協定,或在沒有可用要求時預設為相對路徑。
7.1.1 已過時
已過時控制器中暗示的版面配置查詢,其父項已設定明確的版面配置
class ApplicationController layout "application" end class PostsController < ApplicationController end
在上面的範例中,
PostsController
將不再自動查詢文章版面配置。如果您需要此功能,您可以從ApplicationController
中移除layout "application"
或在PostsController
中明確將其設定為nil
。已過時
ActionController::UnknownAction
,改用AbstractController::ActionNotFound
。已過時
ActionController::DoubleRenderError
,改用AbstractController::DoubleRenderError
。已棄用
method_missing
,改為使用action_missing
以處理遺失的動作。已棄用
ActionController#rescue_action
、ActionController#initialize_template_class
和ActionController#assign_shortcuts
。
7.2 Action Dispatch
新增
config.action_dispatch.default_charset
以設定ActionDispatch::Response
的預設字元集。新增
ActionDispatch::RequestId
中介軟體,它會提供一個獨特的 X-Request-Id 標頭供回應使用,並啟用ActionDispatch::Request#uuid
方法。這使得追蹤堆疊中的端對端請求,以及在混合記錄檔(例如 Syslog)中識別個別請求變得容易。ShowExceptions
中介軟體現在接受例外應用程式,負責在應用程式失敗時呈現例外。應用程式會使用env["action_dispatch.exception"]
中的例外副本以及重新寫入狀態碼的PATH_INFO
來呼叫。允許透過 railtie 設定救援回應,例如
config.action_dispatch.rescue_responses
。
7.2.1 已棄用
- 已棄用在控制器層級設定預設字元集的功能,請改用新的
config.action_dispatch.default_charset
。
7.3 Action View
新增
button_tag
支援至ActionView::Helpers::FormBuilder
。此支援模擬submit_tag
的預設行為。<%= form_for @post do |f| %> <%= f.button %> <% end %>
日期輔助程式接受新的選項
:use_two_digit_numbers => true
,它會呈現月份和日期的選取方塊,並在前面加上零,而不變更各自的值。例如,這對於顯示 ISO 8601 格式的日期(例如「2011-08-01」)很有用。您可以為表單提供命名空間,以確保表單元素中 id 屬性的唯一性。命名空間屬性會在產生的 HTML id 中加上底線作為前綴。
<%= form_for(@offer, :namespace => 'namespace') do |f| %> <%= f.label :version, 'Version' %>: <%= f.text_field :version %> <% end %>
將
select_year
的選項數量限制為 1000。傳遞:max_years_allowed
選項以設定您自己的限制。content_tag_for
和div_for
現在可以接受一組記錄。如果您在區塊中設定接收引數,它也會將記錄作為第一個引數傳遞。因此,您不必執行下列動作@items.each do |item| content_tag_for(:li, item) do Title: <%= item.title %> end end
您可以執行下列動作
content_tag_for(:li, @items) do |item| Title: <%= item.title %> end
新增
font_path
輔助程式方法,用於計算public/fonts
中字型資源的路徑。
7.3.1 已棄用
- 傳遞格式或處理常式給 render :template 及其他類似函式(例如
render :template => "foo.html.erb"
)已棄用。您可以直接提供 :handlers 和 :formats 作為選項:render :template => "foo", :formats => [:html, :js], :handlers => :erb
。
7.4 Sprockets
- 新增設定選項
config.assets.logger
以控制 Sprockets 記錄。將其設定為false
以關閉記錄,設定為nil
則預設為Rails.logger
。
8 Active Record
值為 'on' 和 'ON' 的布林欄位會型別轉換為 true。
當
timestamps
方法建立created_at
和updated_at
欄位時,預設會將它們設為不可為空值。實作
ActiveRecord::Relation#explain
。實作
ActiveRecord::Base.silence_auto_explain
,讓使用者可以在區塊中選擇性停用自動 EXPLAIN。實作自動 EXPLAIN 記錄,用於記錄執行時間較長的查詢。新的設定參數
config.active_record.auto_explain_threshold_in_seconds
決定什麼樣的查詢會被視為執行時間較長。將其設定為 nil 會停用此功能。開發模式下的預設值為 0.5,測試和生產模式下的預設值為 nil。Rails 3.2 在 SQLite、MySQL(mysql2 介面)和 PostgreSQL 中支援此功能。新增
ActiveRecord::Base.store
,用於宣告單一欄位 key/value 儲存。class User < ActiveRecord::Base store :settings, accessors: [ :color, :homepage ] end u = User.new(color: 'black', homepage: '37signals.com') u.color # Accessor stored attribute u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
新增僅針對特定範圍執行遷移的能力,這允許僅執行來自一個引擎的遷移(例如,回復需要移除的引擎所做的變更)。
rake db:migrate SCOPE=blog
從引擎複製的遷移現在會加上引擎名稱作為範圍,例如
01_create_posts.blog.rb
。實作
ActiveRecord::Relation#pluck
方法,可直接從基礎資料表傳回欄位值陣列。這也適用於序列化屬性。Client.where(:active => true).pluck(:id) # SELECT id from clients where active = 1
產生的關聯方法會在一個獨立的模組中建立,以允許覆寫和組成。對於名為 MyModel 的類別,模組會命名為
MyModel::GeneratedFeatureMethods
。它會在 Active Model 中定義的generated_attributes_methods
模組之後立即包含到模型類別中,因此關聯方法會覆寫同名的屬性方法。新增
ActiveRecord::Relation#uniq
以產生唯一的查詢。Client.select('DISTINCT name')
..可以寫成
Client.select(:name).uniq
這也允許你在關聯中還原唯一性
Client.select(:name).uniq.uniq(false)
在 SQLite、MySQL 和 PostgreSQL 適配器中支援索引排序順序。
允許關聯的
:class_name
選項除了字串之外,還可以接受符號。這是為了避免讓新手感到困惑,並與其他選項(例如:foreign_key
)已經允許符號或字串的事實保持一致。has_many :clients, :class_name => :Client # Note that the symbol need to be capitalized
在開發模式中,
db:drop
也會刪除測試資料庫,以與db:create
對稱。不區分大小寫的唯一性驗證會避免在 MySQL 中呼叫 LOWER,當欄位已經使用不區分大小寫的校對時。
交易固定裝置會登錄所有活動資料庫連線。你可以在不同的連線上測試模型,而無需停用交易固定裝置。
新增
first_or_create
、first_or_create!
、first_or_initialize
方法到 Active Record。這是一種比舊的find_or_create_by
動態方法更好的方法,因為它更清楚哪些參數用於尋找記錄,哪些用於建立記錄。User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson")
新增
with_lock
方法到 Active Record 物件,它會開始一個交易,鎖定物件(悲觀的)並傳遞到區塊。此方法會接受一個(可選的)參數,並將它傳遞給lock!
。這使得可以寫下列內容
class Order < ActiveRecord::Base def cancel! transaction do lock! # ... cancelling logic end end end
為
class Order < ActiveRecord::Base def cancel! with_lock do # ... cancelling logic end end end
8.1 已棄用
已棄用在執行緒中自動關閉連線。例如,下列程式碼已棄用
Thread.new { Post.find(1) }.join
應該變更為在執行緒結束時關閉資料庫連線
Thread.new { Post.find(1) Post.connection.close }.join
只有在應用程式程式碼中產生執行緒的人員需要擔心這個變更。
set_table_name
、set_inheritance_column
、set_sequence_name
、set_primary_key
、set_locking_column
方法已棄用。改用指定方法。例如,改用self.table_name=
,而非set_table_name
。class Project < ActiveRecord::Base self.table_name = "project" end
或定義自己的
self.table_name
方法class Post < ActiveRecord::Base def self.table_name "special_" + super end end Post.table_name # => "special_posts"
9 Active Model
新增
ActiveModel::Errors#added?
來檢查是否已新增特定錯誤。新增使用
strict => true
定義嚴格驗證的功能,在驗證失敗時總是引發例外狀況。提供 mass_assignment_sanitizer 作為取代 sanitiser 行為的簡易 API。同時支援 :logger (預設) 和 :strict sanitiser 行為。
9.1 已棄用
已棄用
ActiveModel::AttributeMethods
中的define_attr_method
,因為這只存在於支援 Active Record 中的set_table_name
等方法,而這些方法本身已棄用。已棄用
Model.model_name.partial_path
,改用model.to_partial_path
。
10 Active Resource
- 重新導向回應:303 查看其他和 307 暫時重新導向現在的行為與 301 已永久搬移和 302 已找到相同。
11 Active Support
已新增
ActiveSupport:TaggedLogging
,它可以包裝任何標準Logger
類別以提供標記功能。Logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) Logger.tagged("BCX") { Logger.info "Stuff" } # Logs "[BCX] Stuff" Logger.tagged("BCX", "Jason") { Logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff" Logger.tagged("BCX") { Logger.tagged("Jason") { Logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff"
Date
、Time
和DateTime
中的beginning_of_week
方法接受一個選用引數,代表假設為週開始的那一天。ActiveSupport::Notifications.subscribed
在區塊執行期間提供對事件的訂閱。定義新的方法
Module#qualified_const_defined?
、Module#qualified_const_get
和Module#qualified_const_set
,這些方法類似於標準 API 中對應的方法,但接受限定常數名稱。新增
#deconstantize
,它在變形中補充了#demodulize
。這會移除限定常數名稱中最右邊的區塊。新增
safe_constantize
,它會將字串常數化,但如果常數(或其一部分)不存在,則會傳回nil
,而不是引發例外狀況。使用
Array#extract_options!
時,ActiveSupport::OrderedHash
現在標示為可萃取。新增
Array#prepend
作為Array#unshift
的別名,以及Array#append
作為Array#<<
的別名。Ruby 1.9 的空白字串定義已擴充至 Unicode 空白。此外,在 Ruby 1.8 中,圖形空白 U`3000 被視為空白。
變形器了解縮寫字。
新增
Time#all_day
、Time#all_week
、Time#all_quarter
和Time#all_year
作為產生範圍的方式。Event.where(:created_at => Time.now.all_week) Event.where(:created_at => Time.now.all_day)
新增
instance_accessor: false
作為Class#cattr_accessor
和相關函式的選項。當給定一個以散列方式接受其參數的區塊時,
ActiveSupport::OrderedHash
現在對#each
和#each_pair
有不同的行為。新增
ActiveSupport::Cache::NullStore
,供開發和測試使用。移除
ActiveSupport::SecureRandom
,改用標準函式庫中的SecureRandom
。
11.1 已過時
ActiveSupport::Base64
已過時,改用::Base64
。已過時的
ActiveSupport::Memoizable
,改用 Ruby 記憶模式。Module#synchronize
已過時,沒有替換。請使用 Ruby 標準函式庫中的監視器。已過時的
ActiveSupport::MessageEncryptor#encrypt
和ActiveSupport::MessageEncryptor#decrypt
。ActiveSupport::BufferedLogger#silence
已過時。如果您想要抑制特定區塊的記錄,請變更該區塊的記錄層級。ActiveSupport::BufferedLogger#open_log
已過時。這個方法一開始就不應該公開。ActiveSupport::BufferedLogger
自動建立日誌檔案目錄的行為已過時。請務必在建立執行個體之前建立日誌檔案的目錄。ActiveSupport::BufferedLogger#auto_flushing
已過時。請像這樣設定底層檔案控制代碼的同步層級。或者調整您的檔案系統。現在由檔案系統快取控制沖刷。f = File.open('foo.log', 'w') f.sync = true ActiveSupport::BufferedLogger.new f
ActiveSupport::BufferedLogger#flush
已過時。請設定檔案控制代碼上的同步,或調整您的檔案系統。
12 個學分
請參閱 Rails 貢獻者完整清單,以了解許多人花費許多小時製作 Rails,使其成為穩定且強大的架構。向他們所有人致敬。
Rails 3.2 發行說明由 Vijay Dev 編寫。
回饋
我們鼓勵您協助提升本指南的品質。
如果您發現任何錯字或事實錯誤,請協助我們修正。首先,您可以閱讀我們的 文件貢獻 部分。
您也可能會發現不完整或未更新的內容。請為 main 新增任何遺漏的文件。請務必先查看 Edge Guides,以驗證問題是否已在主分支中修正。查看 Ruby on Rails 指南準則,以了解風格和慣例。
如果您發現需要修正但無法自行修補的任何問題,請 開啟一個問題。
最後但並非最不重要的一點是,我們非常歡迎在 官方 Ruby on Rails 論壇 上針對 Ruby on Rails 文件進行任何類型的討論。