1 升級至 Rails 4.2
如果您要升級現有的應用程式,最好先有良好的測試涵蓋率。您也應該先升級到 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 並查閱它們參考的物件。透過在內部使用 Global ID,將 Active Record 物件作為作業引數傳遞即可正常運作。
例如,如果 trashable
是 Active Record 物件,則此作業可以順利執行,且不涉及任何序列化
class TrashableCleanupJob < ActiveJob::Base
def perform(trashable, depth)
trashable.cleanup(depth)
end
end
請參閱Active Job 基礎指南以取得更多資訊。
2.2 非同步郵件
Action Mailer 現在建立在 Active Job 之上,並隨附 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 Web Console
使用 Rails 4.2 產生新的應用程式現在預設隨附 Web Console gem。Web Console 會在每個錯誤頁面上新增互動式 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 維護。
請參閱這篇部落格文章,以取得有關新清理器變更的更多詳細資訊。
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'
此外,當斷言失敗時,Regexp 替代看起來會有所不同。請注意這裡的 /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 版)。將gem "responders", "~> 2.0"
新增至您的Gemfile
,以繼續使用這些功能。( Pull Request, 更多詳細資訊)移除了已棄用的
AbstractController::Helpers::ClassMethods::MissingHelperError
,改用AbstractController::Helpers::MissingHelperError
。( Commit)
5.2 棄用
棄用了
*_path
輔助程式上的only_path
選項。( Commit)棄用了
assert_tag
、assert_no_tag
、find_tag
和find_all_tag
,改用assert_select
。( Commit)棄用了將路由器的
: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
(Commit)
棄用了 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 現在會自動在 ETags 中包含範本的摘要。( Pull Request)
傳遞至 URL 輔助程式的區段現在會自動逸出。( Commit)
引入了
always_permitted_parameters
選項,以組態全域允許的參數。此組態的預設值為['controller', 'action']
。( Pull Request)新增了來自 RFC 4791 的 HTTP 方法
MKCALENDAR
。( Pull Request)*_fragment.action_controller
通知現在會在酬載中包含控制器和動作名稱。( 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)佔位符 I18n 遵循與
label
I18n 相同的慣例。( Pull Request)
7 Action Mailer
請參閱變更日誌以取得詳細的變更資訊。
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
請參閱變更日誌以取得詳細的變更資訊。
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。(提交)已棄用在不傳遞
:null
選項的情況下使用add_timestamps
和t.timestamps
。null: true
的預設值將在 Rails 5 中變更為null: false
。(提取請求)已棄用
Reflection#source_macro
,且沒有替代方案,因為 Active Record 中不再需要它。(提取請求)已棄用
serialized_attributes
,且沒有替代方案。(提取請求)已棄用在沒有欄位存在時,從
column_for_attribute
回傳nil
。它會在 Rails 5.0 中回傳一個 null 物件。(提取請求)已棄用在不使用替代方案的情況下,將
.joins
、.preload
和.eager_load
用於依賴實例狀態的關聯(即那些使用帶有參數的範圍定義的關聯)。(提交)
8.3 重要變更
SchemaDumper
在create_table
上使用force: :cascade
。這使得在外鍵存在的情況下重新載入綱要成為可能。為單數關聯新增了
:required
選項,它定義了關聯的存在驗證。(提取請求)ActiveRecord::Dirty
現在會偵測對可變值的就地變更。Active Record 模型上的序列化屬性在未變更時不再儲存。這也適用於其他類型,例如 PostgreSQL 上的字串欄位和 json 欄位。(提取請求 1、2、3)引入了
db:purge
Rake 任務,用於清空目前環境的資料庫。(提交)引入了
ActiveRecord::Base#validate!
,如果記錄無效,則會引發ActiveRecord::RecordInvalid
。(提取請求)引入
validate
作為valid?
的別名。(提取請求)touch
現在接受一次觸碰多個屬性。(提取請求)PostgreSQL 配接器現在支援 PostgreSQL 9.4+ 中的
jsonb
資料類型。(提取請求)PostgreSQL 和 SQLite 配接器不再在字串欄位上新增預設的 255 個字元限制。(提取請求)
在 PostgreSQL 配接器中新增了對
citext
欄位類型的支援。(提取請求)在 PostgreSQL 配接器中新增了對使用者建立的範圍類型的支援。(提交)
sqlite3:///some/path
現在解析為絕對系統路徑/some/path
。對於相對路徑,請改用sqlite3:some/path
。(先前,sqlite3:///some/path
解析為相對路徑some/path
。此行為已在 Rails 4.1 中棄用)。(提取請求)新增了
ActiveRecord::Base#pretty_print
以美觀地列印模型。(提取請求)ActiveRecord::Base#reload
現在的行為與m = Model.find(m.id)
相同,表示它不再保留來自自訂SELECT
的額外屬性。(提取請求)ActiveRecord::Base#reflections
現在回傳具有字串鍵而不是符號鍵的雜湊。(提取請求)遷移中的
references
方法現在支援type
選項,用於指定外鍵的類型(例如,:uuid
)。(提取請求)
9 Active Model
請參閱 變更日誌 以取得詳細變更。
9.1 移除
- 已移除已棄用的
Validator#setup
,且沒有替代方案。(提取請求)
9.2 棄用
已棄用
reset_#{attribute}
,改用restore_#{attribute}
。(提取請求)已棄用
ActiveModel::Dirty#reset_changes
,改用clear_changes_information
。(提取請求)
9.3 重要變更
引入
validate
作為valid?
的別名。(提取請求)在
ActiveModel::Dirty
中引入了restore_attributes
方法,以將變更(髒)的屬性還原為它們先前的值。(提取請求 1、2)has_secure_password
預設不再禁止空白密碼(即僅包含空格的密碼)。(提取請求)如果啟用了驗證,
has_secure_password
現在會驗證給定的密碼是否少於 72 個字元。(提取請求)
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 成為如今穩定而強大的框架而花費許多時間的許多人。向他們所有人致敬。