1 升級到 Rails 4.2
如果您要升級現有的應用程式,在開始之前,強烈建議您具備良好的測試涵蓋範圍。如果您尚未升級到 Rails 4.1,您也應先升級到 Rails 4.1,並在嘗試升級到 Rails 4.2 之前,確認您的應用程式仍能如預期般執行。升級時應注意的事項清單,請參閱指南 升級 Ruby on Rails。
2 主要功能
2.1 Active Job
Active Job 是 Rails 4.2 中的新架構。它是佇列系統頂端的共用介面,例如 Resque、Delayed Job、Sidekiq 等。
使用 Active Job API 編寫的作業,由於有各自的轉接器,因此可以在任何受支援的佇列上執行。Active Job 預先設定內嵌執行器,可立即執行作業。
作業通常需要將 Active Record 物件當作引數。Active Job 會傳遞物件參考作為 URI(統一資源識別碼),而不是封送物件本身。新的 Global ID 函式庫會建置 URI,並查詢它們所參照的物件。傳遞 Active Record 物件作為作業引數,只要在內部使用 Global ID,就能順利運作。
例如,如果 trashable
是 Active Record 物件,則此作業會順利執行,而且不涉及序列化
class TrashableCleanupJob < ActiveJob::Base
def perform(trashable, depth)
trashable.cleanup(depth)
end
end
請參閱 Active Job 基礎 指南,以取得更多資訊。
2.2 非同步郵件
建構在 Active Job 之上,Action Mailer 現在附帶一個 deliver_later
方法,透過佇列傳送電子郵件,因此如果佇列是非同步的(預設內嵌佇列會阻擋),它不會阻擋控制器或模型。
使用 deliver_now
仍然可以立即傳送電子郵件。
2.3 Adequate Record
Adequate Record 是 Active Record 中的一組效能改善,讓常見的 find
和 find_by
呼叫,以及一些關聯查詢的速度快上 2 倍。
它的運作方式是將常見的 SQL 查詢快取為已準備的陳述式,並在類似的呼叫中重複使用它們,略過後續呼叫中大部分的查詢產生工作。有關更多詳細資料,請參閱 Aaron Patterson 的部落格文章。
在受支援的操作中,Active Record 將自動利用此功能,而不需要任何使用者參與或程式碼變更。以下是受支援操作的一些範例
Post.find(1) # First call generates and cache the prepared statement
Post.find(2) # Subsequent calls reuse the cached prepared statement
Post.find_by_title('first post')
Post.find_by_title('second post')
Post.find_by(title: 'first post')
Post.find_by(title: 'second post')
post.comments
post.comments(true)
重要的是要強調,正如以上的範例所建議的,已準備的陳述式不會快取在方法呼叫中傳遞的值;相反地,它們有它們的佔位符。
在下列情況中不會使用快取
- 模型有一個預設範圍
- 模型使用單一表格繼承
find
有 id 清單,例如# not cached Post.find(1, 2, 3) Post.find([1,2])
find_by
有 SQL 片段Post.find_by('published_at < ?', 2.weeks.ago)
2.4 網頁主控台
現在使用 Rails 4.2 產生的新應用程式預設附帶 網頁主控台 範例程式。網頁主控台在每個錯誤頁面上新增一個互動式 Ruby 主控台,並提供 console
檢視和控制器輔助程式。
錯誤頁面上的互動式主控台讓您可以在例外狀況發生的位置的內容中執行程式碼。console
輔助程式(如果在檢視或控制器中的任何地方呼叫),會在呈現完成後,使用最終內容啟動一個互動式主控台。
2.5 外來金鑰支援
遷移 DSL 現在支援新增和移除外來鍵。它們也會傾印到 schema.rb
。目前,只有 mysql
、mysql2
和 postgresql
介面支援外來鍵。
# add a foreign key to `articles.author_id` referencing `authors.id`
add_foreign_key :articles, :authors
# add a foreign key to `articles.author_id` referencing `users.lng_id`
add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
# remove the foreign key on `accounts.branch_id`
remove_foreign_key :accounts, :branches
# remove the foreign key on `accounts.owner_id`
remove_foreign_key :accounts, column: :owner_id
請參閱 add_foreign_key 和 remove_foreign_key 的 API 文件,以取得完整說明。
3 不相容性
先前已棄用的功能已移除。請參閱各元件,以取得此版本中新的棄用事項。
下列變更可能需要在升級後立即採取行動。
3.1 使用字串引數的 render
先前,在控制器動作中呼叫 render "foo/bar"
等同於 render file: "foo/bar"
。在 Rails 4.2 中,這已變更為表示 render template: "foo/bar"
。如果您需要呈現檔案,請變更您的程式碼,改用明確形式 (render file: "foo/bar"
)。
3.2 respond_with
/ 類別層級的 respond_to
respond_with
和對應的類別層級 respond_to
已移至 responders gem。將 gem 'responders', '~> 2.0'
新增至您的 Gemfile
以使用它
# app/controllers/users_controller.rb
class UsersController < ApplicationController
respond_to :html, :json
def show
@user = User.find(params[:id])
respond_with @user
end
end
實例層級的 respond_to
不受影響
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
respond_to do |format|
format.html
format.json { render json: @user }
end
end
end
3.3 rails server
的預設主機
由於 Rack 中的變更,rails server
現在預設會在 localhost
上監聽,而不是 0.0.0.0
。這對標準開發工作流程應影響不大,因為 http://127.0.0.1:3000 和 https://127.0.0.1:3000 都會像以前一樣在您自己的電腦上運作。
然而,有了這個變更,您將無法再從不同的機器存取 Rails 伺服器,例如,如果您的開發環境是在虛擬機器中,而您想從主機機器存取它。在這種情況下,請使用 rails server -b 0.0.0.0
啟動伺服器以還原舊行為。
如果您這樣做,請務必正確設定您的防火牆,以便只有您網路上的受信任機器可以存取您的開發伺服器。
3.4 變更 render
的狀態選項符號
由於 Rack 中的變更,render
方法接受的 :status
選項符號已變更
- 306: 已移除
:reserved
。 - 413: 已將
:request_entity_too_large
重新命名為:payload_too_large
。 - 414: 已將
:request_uri_too_long
重新命名為:uri_too_long
。 - 416: 已將
:requested_range_not_satisfiable
重新命名為:range_not_satisfiable
。
請記住,如果使用未知符號呼叫 render
,回應狀態將預設為 500。
3.5 HTML 清理器
HTML 清理器已替換為新的、更強大的實作,建構於 Loofah 和 Nokogiri 之上。新的清理器更安全,其清理功能更強大且靈活。
由於新的演算法,清理後的輸出對於某些病態輸入可能不同。
如果您特別需要舊清理器的確切輸出,您可以將 rails-deprecated_sanitizer gem 新增到 Gemfile
,以採用舊行為。此 gem 沒有發出不建議使用的警告,因為它是選擇加入的。
rails-deprecated_sanitizer
僅支援 Rails 4.2;它不會維護 Rails 5.0。
請參閱這篇部落格文章,以取得有關新 sanitiser 變更的更多詳細資料。
3.6 assert_select
assert_select
現在以Nokogiri為基礎。因此,一些先前有效的選擇器現在不受支援。如果您的應用程式使用任何這些拼寫,您需要更新它們
如果屬性選擇器中的值包含非字母數字字元,則可能需要加上引號。
# before a[href=/] a[href$=/] # now a[href="/"] a[href$="/"]
由包含無效 HTML(元素嵌套不當)的 HTML 來源建立的 DOM 可能有所不同。
例如
# content: <div><i><p></i></div> # before: assert_select('div > i') # => true assert_select('div > p') # => false assert_select('i > p') # => true # now: assert_select('div > i') # => true assert_select('div > p') # => true assert_select('i > p') # => false
如果所選資料包含實體,用於比較的所選值以前是原始的(例如,
AT&T
),現在已評估(例如,AT&T
)。# content: <p>AT&T</p> # before: assert_select('p', 'AT&T') # => true assert_select('p', 'AT&T') # => false # now: assert_select('p', 'AT&T') # => true assert_select('p', 'AT&T') # => false
此外,替換已變更語法。
現在您必須使用類 CSS 的:match
選擇器
assert_select ":match('id', ?)", 'comment_1'
此外,當斷言失敗時,正規表示式替換看起來不同。請注意此處的/hello/
assert_select(":match('id', ?)", /hello/)
變為"(?-mix:hello)"
Expected at least 1 element matching "div:match('id', "(?-mix:hello)")", found 0..
Expected 0 to be >= 1.
請參閱Rails Dom Testing文件,以取得有關assert_select
的更多資訊。
4 Railties
請參閱變更記錄以取得詳細變更。
4.1 移除
--skip-action-view
選項已從應用程式產生器中移除。(Pull Request)rails application
指令已移除,未替換。(Pull Request)
4.2 不建議使用
已棄用生產環境中遺失的
config.log_level
。(Pull Request)已棄用
rake test:all
,建議使用rake test
,因為它現在會執行test
資料夾中的所有測試。(Pull Request)已棄用
rake test:all:db
,建議使用rake test:db
。(Pull Request)已棄用
Rails::Rack::LogTailer
,未替換。(Commit)
4.3 顯著變更
在預設應用程式
Gemfile
中引入web-console
。(Pull Request)在關聯的模型產生器中新增一個
required
選項。(Pull Request)引入
x
名稱空間來定義自訂設定選項# config/environments/production.rb config.x.payment_processing.schedule = :daily config.x.payment_processing.retries = 3 config.x.super_debugger = true
這些選項接著可透過設定物件取得
Rails.configuration.x.payment_processing.schedule # => :daily Rails.configuration.x.payment_processing.retries # => 3 Rails.configuration.x.super_debugger # => true
(Commit)
引入
Rails::Application.config_for
來載入目前環境的設定。# config/exception_notification.yml production: url: http://127.0.0.1:8080 namespace: my_app_production development: url: https://127.0.0.1:3001 namespace: my_app_development
# config/environments/production.rb Rails.application.configure do config.middleware.use ExceptionNotifier, config_for(:exception_notification) end
在應用程式產生器中引入一個
--skip-turbolinks
選項,以不產生 turbolinks 整合。(Commit)引入一個
bin/setup
腳本,作為在應用程式開機時自動化設定程式碼的慣例。(Pull Request)將
config.assets.digest
在開發環境中的預設值變更為true
。(Pull Request)引入一個 API 來註冊
rake notes
的新擴充功能。(Pull Request)引入一個
after_bundle
回呼,供 Rails 範本使用。(Pull Request)引入
Rails.gem_version
作為一個方便的方法,回傳Gem::Version.new(Rails.version)
。(Pull Request)
5 Action Pack
有關詳細變更內容,請參閱 變更日誌。
5.1 已移除
respond_with
和類別層級的respond_to
已從 Rails 中移除,並移至responders
gem(版本 2.0)。在您的Gemfile
中新增gem 'responders', '~> 2.0'
,以繼續使用這些功能。(Pull Request,更多詳細資料)已移除不建議使用的
AbstractController::Helpers::ClassMethods::MissingHelperError
,改用AbstractController::Helpers::MissingHelperError
。(提交)
5.2 不建議使用
已不建議在
*_path
輔助程式中使用only_path
選項。(提交)已不建議使用
assert_tag
、assert_no_tag
、find_tag
和find_all_tag
,改用assert_select
。(提交)已不建議支援將路由器的
:to
選項設定為不包含「#」字元的符號或字串get '/posts', to: MyRackApp => (No change necessary) get '/posts', to: 'post#index' => (No change necessary) get '/posts', to: 'posts' => get '/posts', controller: :posts get '/posts', to: :index => get '/posts', action: :index
(提交)
已不建議在 URL 輔助程式中使用字串金鑰
# bad root_path('controller' => 'posts', 'action' => 'index') # good root_path(controller: 'posts', action: 'index')
5.3 顯著變更
已從文件移除
*_filter
系列方法。不建議使用這些方法,改用*_action
系列方法after_filter => after_action append_after_filter => append_after_action append_around_filter => append_around_action append_before_filter => append_before_action around_filter => around_action before_filter => before_action prepend_after_filter => prepend_after_action prepend_around_filter => prepend_around_action prepend_before_filter => prepend_before_action skip_after_filter => skip_after_action skip_around_filter => skip_around_action skip_before_filter => skip_before_action skip_filter => skip_action_callback
如果您的應用程式目前依賴這些方法,您應該改用替代的
*_action
方法。這些方法未來將不建議使用,最終將從 Rails 中移除。render nothing: true
或呈現nil
主體不再會在回應主體中新增一個空格作為填補。(Pull Request)Rails 現在會自動在 ETag 中包含範本的摘要。(Pull Request)
傳遞到 URL 輔助程式的區段現在會自動轉譯。(提交)
引入了
always_permitted_parameters
選項,用於配置哪些參數在全域被允許。此組態的預設值為['controller', 'action']
。(Pull Request)從 RFC 4791 中新增了 HTTP 方法
MKCALENDAR
。(Pull Request)*_fragment.action_controller
通知現在在 payload 中包含控制器和動作名稱。(Pull Request)改善了路由錯誤頁面,並加入了路由搜尋的模糊比對。(Pull Request)
新增了一個選項,用於停用 CSRF 失敗的記錄。(Pull Request)
當 Rails 伺服器設定為提供靜態資源時,如果客戶端支援且磁碟上有一個預先產生的 gzip 檔案 (
.gz
),現在將會提供 gzip 資源。預設情況下,資源管道會為所有可壓縮的資源產生.gz
檔案。提供 gzip 檔案可以最小化資料傳輸並加速資源請求。如果您在生產環境中從 Rails 伺服器提供資源,請務必 使用 CDN。(Pull Request)在整合測試中呼叫
process
輔助工具時,路徑需要有開頭斜線。以前您可以省略它,但那是實作的副產品,而不是預期的功能,例如:test "list all posts" do get "/posts" assert_response :success end
6 Action View
有關詳細變更,請參閱 變更日誌。
6.1 已棄用
已棄用
AbstractController::Base.parent_prefixes
。當您想要變更尋找檢視的位置時,請覆寫AbstractController::Base.local_prefixes
。(Pull Request)已棄用的
ActionView::Digestor#digest(name, format, finder, options = {})
。應以雜湊方式傳遞參數。(Pull Request)
6.2 顯著變更
render "foo/bar"
現在會擴充為render template: "foo/bar"
,而非render file: "foo/bar"
。(Pull Request)表單輔助程式不再會在隱藏欄位周圍產生具內嵌 CSS 的
<div>
元素。(Pull Request)針對使用集合呈現的部分檢視,引入了
#{partial_name}_iteration
特殊區域變數。它透過index
、size
、first?
和last?
方法,提供對反覆運算目前狀態的存取。(Pull Request)Placeholder I18n 遵循與
label
I18n 相同的慣例。(Pull Request)
7 Action Mailer
請參閱 Changelog 以取得詳細變更。
7.1 已棄用
已棄用郵件程式中的
*_path
輔助程式。請務必改用*_url
輔助程式。(Pull Request)已棄用
deliver
/deliver!
,改用deliver_now
/deliver_now!
。(Pull Request)
7.2 顯著變更
link_to
和url_for
在範本中預設會產生絕對 URL,不再需要傳遞only_path: false
。(Commit)引入了
deliver_later
,它會在應用程式的佇列中排入工作,以非同步方式傳遞電子郵件。(Pull Request)新增
show_previews
組態選項,用於在開發環境以外啟用郵件預覽。(Pull Request)
8 Active Record
請參閱 Changelog 以取得詳細變更。
8.1 已移除
已移除
cache_attributes
及相關函式。所有屬性都已快取。(Pull Request)已移除已棄用的方法
ActiveRecord::Base.quoted_locking_column
。(Pull Request)已移除已棄用的
ActiveRecord::Migrator.proper_table_name
。請改用ActiveRecord::Migration
上的proper_table_name
執行個體方法。(Pull Request)已移除未使用的
:timestamp
類型。在所有情況下,將其透明別名設定為:datetime
。修正當欄位類型傳送至 Active Record 外部(例如 XML 序列化)時的不一致性。(Pull Request)
8.2 已棄用
已棄用
after_commit
和after_rollback
內的錯誤吞嚥。(Pull Request)已棄用
has_many :through
關聯中自動偵測計數快取的錯誤支援。您應該改為手動在透過記錄的has_many
和belongs_to
關聯中指定計數快取。(Pull Request)已棄用將 Active Record 物件傳遞至
.find
或.exists?
。請先在物件上呼叫id
。(Commit 1,2)已棄用對具有排除開頭的 PostgreSQL 範圍值的半生不熟支援。我們目前將 PostgreSQL 範圍對應至 Ruby 範圍。此轉換無法完全執行,因為 Ruby 範圍不支援排除開頭。
目前增加開頭的解決方案不正確,現在已不建議使用。對於我們不知道如何增加的子類型(例如未定義
succ
),它會對具有排除開頭的範圍引發ArgumentError
。(提交)不建議在沒有連線的情況下呼叫
DatabaseTasks.load_schema
。請改用DatabaseTasks.load_schema_current
。(提交)不建議使用
sanitize_sql_hash_for_conditions
,且不提供替代方案。建議使用Relation
來執行查詢和更新,這是首選的 API。(提交)不建議使用
add_timestamps
和t.timestamps
,且不傳遞:null
選項。null: true
的預設值將在 Rails 5 中變更為null: false
。(Pull Request)不建議使用
Reflection#source_macro
,且不提供替代方案,因為 Active Record 不再需要它。(Pull Request)不建議使用
serialized_attributes
,且不提供替代方案。(Pull Request)不建議在沒有欄位時,從
column_for_attribute
傳回nil
。它將在 Rails 5.0 中傳回一個空物件。(Pull Request)不建議在沒有替代方案的情況下,對依賴於實例狀態(即使用需要參數的範圍定義的那些)的關聯使用
.joins
、.preload
和.eager_load
。(提交)
8.3 顯著變更
SchemaDumper
在create_table
上使用force: :cascade
。這使得在有外來鍵時可以重新載入架構。新增一個
:required
選項到單數關聯,用於定義關聯上的存在驗證。(Pull Request)ActiveRecord::Dirty
現在偵測可變值中的就地變更。Active Record 模型中的序列化屬性在未變更時不再儲存。這也適用於 PostgreSQL 中的其他類型,例如字串欄位和 json 欄位。(Pull Request 1、2、3)引入了
db:purge
Rake 任務,用於清空當前環境的資料庫。(提交)引入了
ActiveRecord::Base#validate!
,如果記錄無效,它會引發ActiveRecord::RecordInvalid
。(Pull Request)引入了
validate
作為valid?
的別名。(Pull Request)touch
現在接受一次觸發多個屬性的功能。(Pull Request)PostgreSQL 適配器現在支援 PostgreSQL 9.4+ 中的
jsonb
資料類型。(Pull Request)PostgreSQL 和 SQLite 適配器不再為字串欄位新增預設 255 個字元的限制。(Pull Request)
在 PostgreSQL 適配器中新增了對
citext
欄位類型的支援。(Pull Request)在 PostgreSQL 適配器中新增了對使用者建立的範圍類型的支援。(提交)
sqlite3:///some/path
現在解析為絕對系統路徑/some/path
。對於相對路徑,請改用sqlite3:some/path
。(以前,sqlite3:///some/path
解析為相對路徑some/path
。此行為已在 Rails 4.1 中棄用)。(Pull Request)新增
ActiveRecord::Base#pretty_print
以美化列印模型。(Pull Request)ActiveRecord::Base#reload
現在與m = Model.find(m.id)
行為相同,意即不再保留自訂SELECT
的額外屬性。(Pull Request)ActiveRecord::Base#reflections
現在會傳回字串金鑰的雜湊,而非符號金鑰。(Pull Request)遷移中的
references
方法現在支援type
選項,用於指定外來金鑰的類型(例如::uuid
)。(Pull Request)
9 Active Model
請參閱 變更記錄,以取得詳細變更內容。
9.1 移除
- 移除不建議使用的
Validator#setup
,未提供替代。(Pull Request)
9.2 不建議使用
不建議使用
reset_#{attribute}
,建議改用restore_#{attribute}
。(Pull Request)不建議使用
ActiveModel::Dirty#reset_changes
,建議改用clear_changes_information
。(Pull Request)
9.3 值得注意的變更
引入了
validate
作為valid?
的別名。(Pull Request)在
ActiveModel::Dirty
中新增restore_attributes
方法,用於將已變更(已修改)的屬性還原為先前的值。(Pull Request 1、2)has_secure_password
預設不再禁止空白密碼(即僅包含空白的密碼)。(Pull Request)如果啟用驗證,
has_secure_password
現在會驗證所提供的密碼是否小於 72 個字元。(Pull Request)
10 Active Support
請參閱 變更記錄,以取得詳細變更內容。
10.1 移除
移除已棄用的
Numeric#ago
、Numeric#until
、Numeric#since
、Numeric#from_now
。(提交)移除
ActiveSupport::Callbacks
的已棄用字串終止符。(拉取請求)
10.2 棄用
棄用
Kernel#silence_stderr
、Kernel#capture
和Kernel#quietly
,且不提供替代方案。(拉取請求)棄用
Class#superclass_delegating_accessor
,請改用Class#class_attribute
。(拉取請求)棄用
ActiveSupport::SafeBuffer#prepend!
,因為ActiveSupport::SafeBuffer#prepend
現在執行相同的功能。(拉取請求)
10.3 顯著變更
新增一個新的設定選項
active_support.test_order
,用於指定執行測試案例的順序。此選項目前預設為:sorted
,但在 Rails 5.0 中將變更為:random
。(提交)測試輔助函式
travel_to
現在會將usec
組件截斷為 0。(提交)Object#with_options
現在可以在區塊中使用,而不需要明確的接收器。(拉取請求)新增
String#truncate_words
,用於根據字數截斷字串。(拉取請求)新增
Hash#transform_values
和Hash#transform_values!
,用於簡化常見的模式,其中雜湊的數值必須變更,但鍵保持不變。(拉取請求)humanize
變形輔助程式現在會移除任何開頭底線。(提交)引進
Concern#class_methods
作為module ClassMethods
的替代方案,以及Kernel#concern
以避免module Foo; extend ActiveSupport::Concern; end
樣板。(提交)新的 指南 關於常數自動載入和重新載入。
11 位功臣
請參閱 Rails 貢獻者完整清單,了解許多人花費許多時間,讓 Rails 成為今日穩定且強大的架構。向他們所有人致敬。
回饋
我們鼓勵您協助提升本指南的品質。
如果您發現任何錯字或事實錯誤,請貢獻您的力量。要開始,您可以閱讀我們的 文件貢獻 區段。
您也可能會發現不完整或未更新的內容。請務必為 main 新增任何遺漏的文件。請務必先查看 Edge Guides,以驗證問題是否已在 main 分支中修復。查看 Ruby on Rails 指南準則,了解樣式和慣例。
如果您發現需要修復但無法自行修補的任何原因,請 開啟問題。
最後但並非最不重要的一點是,歡迎在 官方 Ruby on Rails 論壇 上針對 Ruby on Rails 文件進行任何類型的討論。