1 升級至 Rails 3.2
如果您要升級現有的應用程式,最好在開始之前有良好的測試涵蓋率。您也應該先升級至 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 供應商 Gem
Rails 現在使用應用程式根目錄中的 Gemfile
來判斷應用程式啟動所需的 gem。這個 Gemfile
由 Bundler gem 處理,然後安裝所有相依性。它甚至可以將所有相依性在本機安裝到您的應用程式中,使其不依賴系統 gem。
更多資訊:Bundler 首頁
2.2 使用 Edge 版本
Bundler
和 Gemfile
讓使用新的專用 bundle
命令來凍結您的 Rails 應用程式變得輕而易舉。如果您想直接從 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 隨附一個不錯的功能,透過在 ActiveRecord::Relation
中定義 explain
方法來說明 Arel 產生的查詢。例如,您可以執行類似 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 為沒有內容的 API 請求傳回 204 No Content。這讓 scaffold 可以與 jQuery 開箱即用。
更新
Rails::Rack::Logger
中介軟體,將config.log_tags
中設定的任何標籤套用至ActiveSupport::TaggedLogging
。這讓您可以使用子網域和請求 ID 等偵錯資訊輕鬆地標記記錄行,這兩者對於偵錯多使用者生產應用程式非常有幫助。rails new
的預設選項可以在~/.railsrc
中設定。您可以指定每次在主目錄中的.railsrc
設定檔案中執行rails new
時要使用的額外命令列引數。為
destroy
新增別名d
。這也適用於引擎。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
建立索引,後者會是唯一索引。某些型別(如 decimal)接受自訂選項。在範例中,price
將會是一個 decimal 欄位,其精確度和刻度分別設定為 7 和 2。已從預設的
Gemfile
中移除 turn 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 內容中使用。在
caches_page
中新增:gzip
選項。預設選項可以使用page_cache_compression
全域設定。當您使用
:only
和:except
條件指定 layout,但這些條件失敗時,Rails 現在會使用您的預設 layout(例如 "layouts/application")。class CarsController layout 'single_car', :only => :show end
當請求進入
:show
action 時,Rails 會使用layouts/single_car
,而當請求進入其他任何 action 時,則會使用layouts/application
(或layouts/cars
,如果存在)。如果提供
:as
選項,則form_for
會變更為使用#{action}_#{as}
作為 CSS 類別和 id。先前的版本使用#{as}_#{action}
。Active Record 模型上的
ActionController::ParamsWrapper
現在只會封裝已設定的attr_accessible
屬性。如果未設定,則只會封裝類別方法attribute_names
所傳回的屬性。這會修正透過將巢狀屬性加入至attr_accessible
來封裝巢狀屬性的問題。每次 before callback 停止時,都會記錄 "Filter chain halted as CALLBACKNAME rendered or redirected"。
ActionDispatch::ShowExceptions
已重構。controller 負責選擇是否顯示例外狀況。您可以覆寫 controllers 中的show_detailed_exceptions?
,以指定哪些請求應提供錯誤的偵錯資訊。Responders 現在會針對沒有回應主體的 API 請求傳回 204 No Content(如同新的 scaffold)。
ActionController::TestCase
cookies 已重構。現在應該使用cookies[]
為測試案例指派 cookies。cookies[:email] = 'user@example.com' get :index assert_equal 'user@example.com', cookies[:email]
若要清除 cookies,請使用
clear
。cookies.clear get :index assert_nil cookies[:email]
我們現在不再寫出 HTTP_COOKIE,且 cookie jar 會在請求之間保持持續性,因此如果您需要操作測試的環境,您需要在建立 cookie jar 之前執行此操作。
如果未提供
:type
,send_file
現在會從檔案副檔名猜測 MIME 型別。已新增 PDF、ZIP 和其他格式的 MIME 型別條目。
允許
fresh_when/stale?
接受記錄,而不是選項雜湊。將遺失 CSRF token 的警告記錄層級從
:debug
變更為:warn
。Assets 應預設使用請求協定,如果沒有可用的請求,則預設為相對路徑。
7.1.1 已棄用的功能
已棄用在其父系設定了明確 layout 的 controller 中隱含的 layout 查詢。
class ApplicationController layout "application" end class PostsController < ApplicationController end
在以上範例中,
PostsController
將不再自動查詢 posts layout。如果您需要此功能,您可以從ApplicationController
中移除layout "application"
,或在PostsController
中明確地將其設定為nil
。已棄用
ActionController::UnknownAction
,改用AbstractController::ActionNotFound
。已棄用
ActionController::DoubleRenderError
,改用AbstractController::DoubleRenderError
。已棄用
method_missing
,改用action_missing
來處理遺失的 action。已棄用
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 設定 rescue 回應,如
config.action_dispatch.rescue_responses
中所示。
7.2.1 已棄用的功能
- 已棄用在 controller 層級設定預設字元集的功能,請改用新的
config.action_dispatch.default_charset
。
7.3 Action View
新增
button_tag
對ActionView::Helpers::FormBuilder
的支援。此支援模擬submit_tag
的預設行為。<%= form_for @post do |f| %> <%= f.button %> <% end %>
日期 helpers 接受新的選項
:use_two_digit_numbers => true
,該選項會使用前導零來呈現月份和日期的選取方塊,而不會變更各自的值。例如,這對於顯示 '2011-08-01' 等 ISO 8601 樣式的日期很有用。您可以為表單提供命名空間,以確保表單元素上的 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
helper 方法,該方法會計算public/fonts
中字型 asset 的路徑。
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
欄位時,預設會使其為不可為 null。已實作
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
,以宣告簡單的單欄鍵/值儲存區。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")
為 Active Record 物件新增
with_lock
方法,該方法會啟動交易、鎖定物件(悲觀式)並產生區塊。此方法會接受一個(選擇性)參數,並將其傳遞至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 作為一個簡單的 API 來取代 sanitizer 的行為。同時也支援 :logger (預設) 和 :strict 這兩種 sanitizer 行為。
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 See Other 和 307 Temporary Redirect 現在的行為類似於 301 Moved Permanently 和 302 Found。
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
,它補充了 inflections 中的#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 被視為空白字元。
inflector 可以理解縮寫。
新增了
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
及其相關方法的選項。當給定一個接受帶 splat 參數的區塊時,
ActiveSupport::OrderedHash
現在對#each
和#each_pair
有不同的行為。新增了
ActiveSupport::Cache::NullStore
,用於開發和測試。移除了
ActiveSupport::SecureRandom
,改用標準程式庫中的SecureRandom
。
11.1 已棄用
已棄用
ActiveSupport::Base64
,改用::Base64
。已棄用
ActiveSupport::Memoizable
,改用 Ruby 的 memoization 模式。Module#synchronize
已被棄用,沒有替代方法。請使用 ruby 標準程式庫中的 monitor。已棄用
ActiveSupport::MessageEncryptor#encrypt
和ActiveSupport::MessageEncryptor#decrypt
。已棄用
ActiveSupport::BufferedLogger#silence
。如果您想在特定區塊中抑制日誌,請變更該區塊的日誌級別。已棄用
ActiveSupport::BufferedLogger#open_log
。這個方法一開始就不應該是公開的。ActiveSupport::BufferedLogger
自動為您的日誌檔案建立目錄的行為已被棄用。請確保在實例化之前為您的日誌檔案建立目錄。已棄用
ActiveSupport::BufferedLogger#auto_flushing
。請像這樣設定底層檔案控制代碼的同步級別。或調整您的檔案系統。現在由 FS 快取控制刷新。f = File.open('foo.log', 'w') f.sync = true ActiveSupport::BufferedLogger.new f
已棄用
ActiveSupport::BufferedLogger#flush
。請設定檔案控制代碼的同步,或調整您的檔案系統。
12 貢獻者
請參閱 Rails 的完整貢獻者列表,了解許多人花了許多時間讓 Rails 成為現在穩定且強大的框架。向他們所有人致敬。
Rails 3.2 發行說明由 Vijay Dev 編寫。