更多資訊請參閱 rubyonrails.org:

升級 Ruby on Rails

本指南提供將應用程式升級至較新版本 Ruby on Rails 時應遵循的步驟。這些步驟也適用於個別發行指南。

1 一般建議

在嘗試升級現有應用程式之前,您應該確定自己有充分的理由進行升級。您需要權衡多個因素:對新功能的需求、尋找舊程式碼支援的難度增加,以及您可用的時間和技能,僅舉幾例。

1.1 測試覆蓋率

為了確保您的應用程式在升級後仍能正常運作,最好的方法是在開始升級流程之前就擁有良好的測試覆蓋率。如果您沒有自動化測試來驗證應用程式的大部分功能,您就需要花時間手動測試所有變更的部分。以 Rails 升級為例,這將意味著應用程式中的每一項功能都必須測試。為了您自己好,請在開始升級之前確保您的測試覆蓋率良好。

1.2 Ruby 版本

Rails 通常在發佈時會與最新發佈的 Ruby 版本保持接近。

  • Rails 8.0 需要 Ruby 3.2.0 或更新版本。
  • Rails 7.2 需要 Ruby 3.1.0 或更新版本。
  • Rails 7.0 和 7.1 需要 Ruby 2.7.0 或更新版本。
  • Rails 6 需要 Ruby 2.5.0 或更新版本。
  • Rails 5 需要 Ruby 2.2.2 或更新版本。

最好將 Ruby 和 Rails 分開升級。先升級到您能使用的最新 Ruby 版本,然後再升級 Rails。

1.3 升級流程

在變更 Rails 版本時,最好一次移動一個小版本,以便充分利用棄用警告。Rails 版本號的格式為 Major.Minor.Patch。主要版本(Major)和小版本(Minor)允許對公共 API 進行變更,這可能會導致您的應用程式出現錯誤。修補版本(Patch)僅包含錯誤修復,不會變更任何公共 API。

升級流程應如下:

  1. 撰寫測試並確保測試通過。
  2. 移動到目前版本後的最新修補版本。
  3. 修復測試和已棄用的功能。
  4. 移動到下一個小版本的最新修補版本。

重複此流程,直到達到您的目標 Rails 版本。

1.3.1 版本之間的移動

要在版本之間移動:

  1. 變更 Gemfile 中的 Rails 版本號,並執行 bundle update rails
  2. 如果執行 jsbundling-rails,請在 package.json 中變更 Rails JavaScript 套件的版本,並執行 bin/rails javascript:install
  3. 執行更新任務
  4. 執行您的測試。

您可以在這裡找到所有已發佈的 Rails gem 清單。

1.4 更新任務

Rails 提供 rails app:update 命令。在更新 Gemfile 中的 Rails 版本後,執行此命令。這將在互動式會話中幫助您建立新檔案並變更舊檔案。

$ bin/rails app:update
       exist  config
    conflict  config/application.rb
Overwrite /myapp/config/application.rb? (enter "h" for help) [Ynaqdh]
       force  config/application.rb
      create  config/initializers/new_framework_defaults_8_0.rb
...

別忘了檢查差異,看看是否有任何意外變更。請注意,在此過程中使用的 diff 和 merge 工具可以使用 THOR_DIFFTHOR_MERGE 環境變數來定義。

1.5 設定框架預設值

新的 Rails 版本可能具有與先前版本不同的組態預設值。但是,在遵循上述步驟之後,您的應用程式仍將以先前 Rails 版本的組態預設值執行。這是因為 config/application.rb 中的 config.load_defaults 的值尚未變更。

為了讓您能夠逐一升級到新的預設值,更新任務已建立一個檔案 config/initializers/new_framework_defaults_X.Y.rb(檔案名稱中包含所需的 Rails 版本)。您應該透過取消註解檔案中的內容來啟用新的組態預設值;這可以在多次部署中逐步完成。一旦您的應用程式準備好使用新的預設值執行,您可以移除此檔案並切換 config.load_defaults 的值。

2 從 Rails 7.2 升級到 Rails 8.0

有關 Rails 8.0 所做變更的更多資訊,請參閱發行說明

3 從 Rails 7.1 升級到 Rails 7.2

有關 Rails 7.2 所做變更的更多資訊,請參閱發行說明

3.1 現在所有測試都遵守 active_job.queue_adapter 設定

如果您在 config/application.rbconfig/environments/test.rb 檔案中設定了 config.active_job.queue_adapter,您選擇的適配器先前並未在所有測試中一致地使用。在某些測試中會使用您的適配器,但在其他測試中則會使用 TestAdapter

在 Rails 7.2 中,如果提供了 queue_adapter 設定,所有測試都會遵守該設定。如果您將 queue_adapter 設定為 :test 以外的值,但撰寫的測試方式卻依賴於 TestAdapter,這可能會導致測試錯誤。

如果未提供任何設定,則會繼續使用 TestAdapter

4 從 Rails 7.0 升級到 Rails 7.1

有關 Rails 7.1 所做變更的更多資訊,請參閱發行說明

4.1 開發和測試環境的 secret_key_base 檔案已變更

在開發和測試環境中,Rails 從中讀取 secret_key_base 的檔案已從 tmp/development_secret.txt 重新命名為 tmp/local_secret.txt

您可以簡單地將先前的檔案重新命名為 local_secret.txt 以繼續使用相同的密鑰,或將密鑰從先前的檔案複製到新檔案。

如果沒有這樣做,Rails 會在應用程式載入時在新檔案 tmp/local_secret.txt 中產生新的密鑰。

這將使開發和測試環境中的所有現有會話/Cookie 無效,也會導致其他從 secret_key_base 衍生的簽章中斷,例如 Active Storage/Action Text 附件。

生產和其他環境不受影響。

4.2 自動載入的路徑不再位於 $LOAD_PATH 中

從 Rails 7.1 開始,自動載入器管理的目錄不再新增到 $LOAD_PATH 中。這表示無法使用手動 require 呼叫來載入其檔案,這無論如何都不應該這樣做。

減少 $LOAD_PATH 的大小可以加快未使用 bootsnap 的應用程式的 require 呼叫速度,並減少其他應用程式的 bootsnap 快取大小。

如果您希望這些路徑仍然位於 $LOAD_PATH 中,您可以選擇加入

config.add_autoload_paths_to_load_path = true

但不建議這樣做,自動載入路徑中的類別和模組應該要自動載入。也就是說,只需參考它們即可。

lib 目錄不受此旗標影響,它始終會新增到 $LOAD_PATH 中。

4.3 config.autoload_lib 和 config.autoload_lib_once

如果您的應用程式的自動載入或自動載入一次路徑中沒有 lib,請跳過此章節。您可以透過檢查輸出來得知

# Print autoload paths.
$ bin/rails runner 'pp Rails.autoloaders.main.dirs'

# Print autoload once paths.
$ bin/rails runner 'pp Rails.autoloaders.once.dirs'

如果您的應用程式的自動載入路徑中已經有 lib,通常在 config/application.rb 中會有類似以下的設定

# Autoload lib, but do not eager load it (maybe overlooked).
config.autoload_paths << config.root.join("lib")

# Autoload and also eager load lib.
config.autoload_paths << config.root.join("lib")
config.eager_load_paths << config.root.join("lib")

# Same, because all eager load paths become autoload paths too.
config.eager_load_paths << config.root.join("lib")

這仍然有效,但建議將這些行替換為更簡潔的

config.autoload_lib(ignore: %w(assets tasks))

請將任何其他不包含 .rb 檔案,或不應該重新載入或預先載入的 lib 子目錄新增到 ignore 清單中。例如,如果您的應用程式有 lib/templateslib/generatorslib/middleware,您會新增相對於 lib 的名稱

config.autoload_lib(ignore: %w(assets tasks templates generators middleware))

透過這一行程式碼,如果 config.eager_loadtrueproduction 模式下的預設值),lib 中(未忽略的)程式碼也會預先載入。這通常是您想要的,但如果之前未將 lib 新增到預先載入路徑中,並且您仍然希望這樣做,請選擇退出

Rails.autoloaders.main.do_not_eager_load(config.root.join("lib"))

如果應用程式在 config.autoload_once_paths 中有 lib,則 config.autoload_lib_once 方法與之類似。

4.4 ActiveStorage::BaseController 不再包含串流關注點

繼承自 ActiveStorage::BaseController 並使用串流來實作自訂檔案服務邏輯的應用程式控制器現在必須明確包含 ActiveStorage::Streaming 模組。

4.5 MemCacheStoreRedisCacheStore 現在預設使用連線池

connection_pool gem 已新增為 activesupport gem 的依賴項,MemCacheStoreRedisCacheStore 現在預設使用連線池。

如果您不想使用連線池,請在設定快取儲存時將 :pool 選項設定為 false

config.cache_store = :mem_cache_store, "cache.example.com", { pool: false }

如需更多資訊,請參閱使用 Rails 快取指南。

4.6 SQLite3Adapter 現在已設定為以嚴格字串模式使用

使用嚴格字串模式會停用雙引號字串文字。

SQLite 對雙引號字串文字有一些怪癖。它首先嘗試將雙引號字串視為識別碼名稱,但如果它們不存在,則會將它們視為字串文字。因此,錯誤可能會在不知不覺中發生。例如,可以為不存在的欄建立索引。有關更多詳細資訊,請參閱 SQLite 文件

如果您不想以嚴格模式使用 SQLite3Adapter,您可以停用此行為

# config/application.rb
config.active_record.sqlite3_adapter_strict_strings_by_default = false

4.7 支援 ActionMailer::Preview 的多個預覽路徑

選項 config.action_mailer.preview_path 已棄用,改用 config.action_mailer.preview_paths。將路徑附加到此設定選項會導致在搜尋郵件程式預覽時使用這些路徑。

config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"

4.8 config.i18n.raise_on_missing_translations = true 現在會在任何遺失的翻譯上引發錯誤。

先前,它只會在視圖或控制器中呼叫時引發錯誤。現在,只要 I18n.t 收到無法識別的索引鍵時,就會引發錯誤。

# with config.i18n.raise_on_missing_translations = true

# in a view or controller:
t("missing.key") # raises in 7.0, raises in 7.1
I18n.t("missing.key") # didn't raise in 7.0, raises in 7.1

# anywhere:
I18n.t("missing.key") # didn't raise in 7.0, raises in 7.1

如果您不希望這種行為,您可以設定 config.i18n.raise_on_missing_translations = false

# with config.i18n.raise_on_missing_translations = false

# in a view or controller:
t("missing.key") # didn't raise in 7.0, doesn't raise in 7.1
I18n.t("missing.key") # didn't raise in 7.0, doesn't raise in 7.1

# anywhere:
I18n.t("missing.key") # didn't raise in 7.0, doesn't raise in 7.1

或者,您可以自訂 I18n.exception_handler。如需更多資訊,請參閱 i18n 指南

AbstractController::Translation.raise_on_missing_translations 已移除。這是一個私有 API,如果您依賴它,您應該遷移到 config.i18n.raise_on_missing_translations 或自訂的例外處理程式。

4.9 bin/rails test 現在會執行 test:prepare 任務

當透過 bin/rails test 執行測試時,rake test:prepare 任務會在測試執行前執行。如果您增強了 test:prepare 任務,您的增強功能會在您的測試之前執行。tailwindcss-railsjsbundling-railscssbundling-rails 都會增強此任務,其他第三方 gem 也會。

請參閱測試 Rails 應用程式指南以獲取更多資訊。

如果您執行單一檔案的測試 (bin/rails test test/models/user_test.rb),test:prepare 將不會在其之前執行。

4.10@rails/ujs 匯入語法已修改

從 Rails 7.1 開始,從 @rails/ujs 匯入模組的語法已修改。Rails 不再支援直接從 @rails/ujs 匯入模組。

例如,嘗試從該函式庫匯入函式將會失敗

import { fileInputSelector } from "@rails/ujs"
// ERROR: export 'fileInputSelector' (imported as 'fileInputSelector') was not found in '@rails/ujs' (possible exports: default)

在 Rails 7.1 中,使用者應該先直接從 @rails/ujs 匯入 Rails 物件。然後,使用者可以從 Rails 物件匯入特定的模組。

以下顯示 Rails 7.1 中的匯入範例

import Rails from "@rails/ujs"
// Alias the method
const fileInputSelector = Rails.fileInputSelector
// Alternatively, reference it from the Rails object where it is used
Rails.fileInputSelector(...)

4.11 Rails.logger 現在會回傳 ActiveSupport::BroadcastLogger 實例

ActiveSupport::BroadcastLogger 類別是一個新的記錄器,可以輕鬆地將日誌廣播到不同的接收器 (STDOUT、日誌檔案...)。

廣播日誌的 API (使用 ActiveSupport::Logger.broadcast 方法) 已移除,且先前為私有的。如果您的應用程式或函式庫依賴此 API,您需要進行以下變更

logger = Logger.new("some_file.log")

# Before

Rails.logger.extend(ActiveSupport::Logger.broadcast(logger))

# After

Rails.logger.broadcast_to(logger)

如果您的應用程式已設定自訂記錄器,Rails.logger 會將所有方法包裝並代理給它。您的部分不需要變更即可使其運作。

如果您需要存取您的自訂記錄器實例,您可以使用 broadcasts 方法來執行此操作

# config/application.rb
config.logger = MyLogger.new

# Anywhere in your application
puts Rails.logger.class #=> BroadcastLogger
puts Rails.logger.broadcasts #=> [MyLogger]

4.12 Active Record 加密演算法變更

Active Record 加密現在使用 SHA-256 作為其雜湊摘要演算法。如果您有使用先前 Rails 版本加密的資料,則需要考慮兩種情況

  1. 如果您將 config.active_support.key_generator_hash_digest_class 設定為 SHA-1 (Rails 7.0 之前的預設值),您也需要為 Active Record 加密設定 SHA-1

    config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1
    
  2. 如果您將 config.active_support.key_generator_hash_digest_class 設定為 SHA-256 (7.0 中的新預設值),則您需要為 Active Record 加密設定 SHA-256

    config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256
    

請參閱設定 Rails 應用程式指南,以獲取有關 config.active_record.encryption.hash_digest_class 的更多資訊。

此外,還引入了一個新的設定config.active_record.encryption.support_sha1_for_non_deterministic_encryption 來解決 一個錯誤,該錯誤導致某些屬性即使透過上述 hash_digest_class 設定配置了 SHA-256,也會使用 SHA-1 進行加密。

預設情況下,config.active_record.encryption.support_sha1_for_non_deterministic_encryption 在 Rails 7.1 中已停用。如果您擁有在 Rails < 7.1 版本中加密的資料,並且您認為可能受到上述錯誤的影響,則應啟用此設定

config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true

如果您正在使用加密資料,請仔細查看以上內容。

4.13 在 Controller 測試、整合測試和系統測試中處理異常的新方法

config.action_dispatch.show_exceptions 設定控制 Action Pack 如何處理回應請求時引發的異常。

在 Rails 7.1 之前,設定 config.action_dispatch.show_exceptions = true 會設定 Action Pack 來救援異常並呈現適當的 HTML 錯誤頁面,例如使用 404 Not found 狀態碼呈現 public/404.html 而不是引發 ActiveRecord::RecordNotFound 異常。設定 config.action_dispatch.show_exceptions = false 會設定 Action Pack 來不救援異常。在 Rails 7.1 之前,新應用程式會使用 config/environments/test.rb 中的一行程式碼來設定 config.action_dispatch.show_exceptions = false

Rails 7.1 將可接受的值從 truefalse 變更為 :all:rescuable:none

  • :all - 針對所有異常呈現 HTML 錯誤頁面 (相當於 true)
  • :rescuable - 針對 config.action_dispatch.rescue_responses 宣告的異常呈現 HTML 錯誤頁面
  • :none (相當於 false) - 不救援任何異常

由 Rails 7.1 或更新版本產生的應用程式會在它們的 config/environments/test.rb 中設定 config.action_dispatch.show_exceptions = :rescuable。升級時,現有的應用程式可以將 config.action_dispatch.show_exceptions = :rescuable 變更為使用新的行為,或將舊的值替換為對應的新值 (true 替換 :allfalse 替換 :none)。

5 從 Rails 6.1 升級到 Rails 7.0

有關對 Rails 7.0 所做的變更的更多資訊,請參閱發行說明

5.1 ActionView::Helpers::UrlHelper#button_to 行為已變更

從 Rails 7.0 開始,如果使用持續性的 Active Record 物件來建立按鈕 URL,button_to 會呈現具有 patch HTTP 動詞的 form 標籤。為了保持目前行為,請考慮明確傳遞 method: 選項

-button_to("Do a POST", [:my_custom_post_action_on_workshop, Workshop.find(1)])
+button_to("Do a POST", [:my_custom_post_action_on_workshop, Workshop.find(1)], method: :post)

或使用輔助方法來建立 URL

-button_to("Do a POST", [:my_custom_post_action_on_workshop, Workshop.find(1)])
+button_to("Do a POST", my_custom_post_action_on_workshop_workshop_path(Workshop.find(1)))

5.2 Spring

如果您的應用程式使用 Spring,則需要將其升級到至少 3.0.0 版本。否則,您會收到

undefined method `mechanism=' for ActiveSupport::Dependencies:Module

此外,請確保 config.cache_classesconfig/environments/test.rb 中設定為 false

5.3 Sprockets 現在是可選的相依性

gem rails 不再依賴 sprockets-rails。如果您的應用程式仍然需要使用 Sprockets,請務必將 sprockets-rails 新增至您的 Gemfile。

gem "sprockets-rails"

5.4 應用程式需要在 zeitwerk 模式下執行

仍然在 classic 模式下執行的應用程式必須切換到 zeitwerk 模式。請查看 Classic to Zeitwerk HOWTO 指南以獲取詳細資訊。

5.5 setter config.autoloader= 已刪除

在 Rails 7 中,沒有設定自動載入模式的設定點,config.autoloader= 已刪除。如果您出於任何原因將其設定為 :zeitwerk,請將其移除。

5.6 ActiveSupport::Dependencies 私有 API 已刪除

ActiveSupport::Dependencies 的私有 API 已刪除。這包括像 hook!unhook!depend_onrequire_or_loadmechanism 和許多其他方法。

以下是一些重點

  • 如果您使用 ActiveSupport::Dependencies.constantizeActiveSupport::Dependencies.safe_constantize,只需將其變更為 String#constantizeString#safe_constantize
  ActiveSupport::Dependencies.constantize("User") # NO LONGER POSSIBLE
  "User".constantize # 👍
  • ActiveSupport::Dependencies.mechanism 的任何使用 (讀取器或寫入器) 都必須透過存取 config.cache_classes 來相應地取代。

  • 如果您想追蹤自動載入器的活動,ActiveSupport::Dependencies.verbose= 不再可用,只需在 config/application.rb 中抛出 Rails.autoloaders.log!

輔助內部類別或模組也已消失,例如 ActiveSupport::Dependencies::ReferenceActiveSupport::Dependencies::Blamable 和其他。

5.7 初始化期間的自動載入

to_prepare 區塊之外,在初始化期間自動載入可重新載入常數的應用程式,會卸載這些常數,並且自 Rails 6.0 以來會發出此警告

DEPRECATION WARNING: Initialization autoloaded the constant ....

Being able to do this is deprecated. Autoloading during initialization is going
to be an error condition in future versions of Rails.

...

如果您仍然在日誌中收到此警告,請查看 自動載入指南中關於應用程式啟動時自動載入的部分。否則,您會在 Rails 7 中收到 NameError

once 自動載入器管理的常數可以在初始化期間自動載入,並且它們可以正常使用,不需要 to_prepare 區塊。但是,現在會更早設定 once 自動載入器以支援此功能。如果應用程式有自訂的 inflections,並且 once 自動載入器應該知道它們,則您需要將 config/initializers/inflections.rb 中的程式碼移至 config/application.rb 中應用程式類別定義的主體中

module MyApp
  class Application < Rails::Application
    # ...

    ActiveSupport::Inflector.inflections(:en) do |inflect|
      inflect.acronym "HTML"
    end
  end
end

5.8 設定 config.autoload_once_paths 的能力

config.autoload_once_paths 可以設定在 config/application.rb 中定義的應用程式類別的主體中,或設定在 config/environments/* 中環境的設定中。

同樣地,引擎可以在引擎類別的主體中或環境的設定中設定該集合。

在那之後,該集合會被凍結,您可以從那些路徑自動載入。特別是,您可以在初始化期間從那裡自動載入。它們由 Rails.autoloaders.once 自動載入器管理,該自動載入器不重新載入,僅自動載入/急切載入。

如果您在處理環境設定之後設定此設定,並且收到 FrozenError,請移動程式碼。

5.9 ActionDispatch::Request#content_type 現在會傳回 Content-Type 標頭,如同它本身。

先前,ActionDispatch::Request#content_type 傳回的值不包含字元集部分。此行為已變更為傳回包含字元集部分的 Content-Type 標頭,如同它本身。

如果您只想要 MIME 類型,請改用 ActionDispatch::Request#media_type

之前

request = ActionDispatch::Request.new("CONTENT_TYPE" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET")
request.content_type #=> "text/csv"

之後

request = ActionDispatch::Request.new("Content-Type" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET")
request.content_type #=> "text/csv; header=present; charset=utf-16"
request.media_type   #=> "text/csv"

金鑰產生器的預設摘要類別正從 SHA1 變更為 SHA256。這會對 Rails 產生的任何加密訊息產生影響,包括加密的 Cookie。

為了能夠讀取使用舊摘要類別的訊息,必須註冊輪換器。未能這樣做可能會導致使用者在升級期間的會話失效。

以下是加密和簽署的 Cookie 的輪換器範例。

# config/initializers/cookie_rotator.rb
Rails.application.config.after_initialize do
  Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies|
    authenticated_encrypted_cookie_salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt
    signed_cookie_salt = Rails.application.config.action_dispatch.signed_cookie_salt

    secret_key_base = Rails.application.secret_key_base

    key_generator = ActiveSupport::KeyGenerator.new(
      secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1
    )
    key_len = ActiveSupport::MessageEncryptor.key_len

    old_encrypted_secret = key_generator.generate_key(authenticated_encrypted_cookie_salt, key_len)
    old_signed_secret = key_generator.generate_key(signed_cookie_salt)

    cookies.rotate :encrypted, old_encrypted_secret
    cookies.rotate :signed, old_signed_secret
  end
end

5.11 ActiveSupport::Digest 的摘要類別變更為 SHA256

ActiveSupport::Digest 的預設摘要類別正從 SHA1 變更為 SHA256。這會對諸如 Etag 之類的事物產生影響,這些事物會變更和快取金鑰也是如此。變更這些金鑰可能會影響快取命中率,因此在升級到新的雜湊時,請小心並留意這一點。

5.12 新的 ActiveSupport::Cache 序列化格式

引入了更快、更精簡的序列化格式。

要啟用它,您必須設定 config.active_support.cache_format_version = 7.0

# config/application.rb

config.load_defaults 6.1
config.active_support.cache_format_version = 7.0

或簡單地

# config/application.rb

config.load_defaults 7.0

然而,Rails 6.1 應用程式無法讀取這種新的序列化格式,因此為了確保無縫升級,您必須先使用 config.active_support.cache_format_version = 6.1 部署 Rails 7.0 的升級,然後只有在所有 Rails 程序都更新後,才能設定 config.active_support.cache_format_version = 7.0

Rails 7.0 可以讀取兩種格式,因此在升級期間快取不會失效。

5.13 Active Storage 影片預覽圖片生成

影片預覽圖片生成現在使用 FFmpeg 的場景變更偵測來產生更有意義的預覽圖片。先前會使用影片的第一個影格,如果影片從黑色淡入,就會造成問題。此變更需要 FFmpeg v3.4 以上版本。

5.14 Active Storage 預設變體處理器變更為 :vips

對於新的應用程式,圖片轉換將使用 libvips 而不是 ImageMagick。這將減少產生變體所需的時間,以及 CPU 和記憶體使用量,從而提高依賴 Active Storage 提供圖片的應用程式的回應時間。

:mini_magick 選項並未被棄用,因此可以繼續使用。

若要將現有的應用程式遷移到 libvips,請設定

Rails.application.config.active_storage.variant_processor = :vips

然後您需要將現有的圖片轉換程式碼變更為 image_processing 巨集,並將 ImageMagick 的選項替換為 libvips 的選項。

5.14.1 將 resize 替換為 resize_to_limit

- variant(resize: "100x")
+ variant(resize_to_limit: [100, nil])

如果您不這樣做,當您切換到 vips 時,您會看到這個錯誤:no implicit conversion to float from string

5.14.2 裁切時使用陣列

- variant(crop: "1920x1080+0+0")
+ variant(crop: [0, 0, 1920, 1080])

如果您在遷移到 vips 時不這樣做,您會看到以下錯誤:unable to call crop: you supplied 2 arguments, but operation needs 5

5.14.3 限制您的裁切值

Vips 在裁切方面比 ImageMagick 更嚴格

  1. 如果 x 和/或 y 是負值,它將不會裁切。例如:[-10, -10, 100, 100]
  2. 如果位置 (xy) 加上裁切尺寸 (widthheight) 大於圖片,它將不會裁切。例如:一張 125x125 的圖片和一個 [50, 50, 100, 100] 的裁切。

如果您在遷移到 vips 時不這樣做,您會看到以下錯誤:extract_area: bad extract area

5.14.4 調整 resize_and_pad 使用的背景顏色

Vips 使用黑色作為 resize_and_pad 的預設背景顏色,而不是像 ImageMagick 一樣使用白色。請使用 background 選項來修正此問題

- variant(resize_and_pad: [300, 300])
+ variant(resize_and_pad: [300, 300, background: [255]])

5.14.5 移除任何基於 EXIF 的旋轉

Vips 在處理變體時會使用 EXIF 值自動旋轉圖片。如果您先前儲存了使用者上傳照片的旋轉值,以便使用 ImageMagick 應用旋轉,您必須停止這樣做

- variant(format: :jpg, rotate: rotation_value)
+ variant(format: :jpg)

5.14.6 將 monochrome 替換為 colourspace

Vips 使用不同的選項來製作單色圖片

- variant(monochrome: true)
+ variant(colourspace: "b-w")

5.14.7 切換到 libvips 選項以壓縮圖片

JPEG

- variant(strip: true, quality: 80, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB")
+ variant(saver: { strip: true, quality: 80, interlace: true })

PNG

- variant(strip: true, quality: 75)
+ variant(saver: { strip: true, compression: 9 })

WEBP

- variant(strip: true, quality: 75, define: { webp: { lossless: false, alpha_quality: 85, thread_level: 1 } })
+ variant(saver: { strip: true, quality: 75, lossless: false, alpha_q: 85, reduction_effort: 6, smart_subsample: true })

GIF

- variant(layers: "Optimize")
+ variant(saver: { optimize_gif_frames: true, optimize_gif_transparency: true })

5.14.8 部署到生產環境

Active Storage 會將必須執行的轉換列表編碼到圖片的網址中。如果您的應用程式快取了這些網址,當您將新程式碼部署到生產環境後,您的圖片將會損壞。因此,您必須手動使受影響的快取鍵失效。

例如,如果您在視圖中有類似這樣的程式碼

<% @products.each do |product| %>
  <% cache product do %>
    <%= image_tag product.cover_photo.variant(resize: "200x") %>
  <% end %>
<% end %>

您可以透過觸摸產品或變更快取鍵來使快取失效

<% @products.each do |product| %>
  <% cache ["v2", product] do %>
    <%= image_tag product.cover_photo.variant(resize_to_limit: [200, nil]) %>
  <% end %>
<% end %>

5.15 Rails 版本現在包含在 Active Record 綱要傾印中

Rails 7.0 變更了一些欄位類型的預設值。為了避免從 6.1 升級到 7.0 的應用程式使用新的 7.0 預設值載入目前的綱要,Rails 現在會在綱要傾印中包含框架的版本。

在 Rails 7.0 中首次載入綱要之前,請務必執行 rails app:update,以確保綱要的版本包含在綱要傾印中。

綱要檔案將如下所示

# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[6.1].define(version: 2022_01_28_123512) do
  # ...
end

當您第一次使用 Rails 7.0 傾印綱要時,您會看到該檔案的許多變更,包括一些欄位資訊。請務必檢閱新的綱要檔案內容並將其提交到您的儲存庫。

6 從 Rails 6.0 升級到 Rails 6.1

有關 Rails 6.1 所做變更的更多資訊,請參閱發行說明

6.1 Rails.application.config_for 的傳回值不再支援使用字串索引鍵存取。

假設有類似這樣的設定檔

# config/example.yml
development:
  options:
    key: value
Rails.application.config_for(:example).options

這先前會傳回一個雜湊,您可以使用字串索引鍵存取值。這在 6.0 中已棄用,現在已不再有效。

如果您仍然想要使用字串索引鍵存取值,您可以對 config_for 的傳回值呼叫 with_indifferent_access,例如

Rails.application.config_for(:example).with_indifferent_access.dig("options", "key")

6.2 使用 respond_to#any 時,回應的 Content-Type

回應中傳回的 Content-Type 標頭可能與 Rails 6.0 傳回的不同,更具體地說,如果您的應用程式使用 respond_to { |format| format.any }。Content-Type 現在將基於給定的區塊,而不是請求的格式。

範例

def my_action
  respond_to do |format|
    format.any { render(json: { foo: "bar" }) }
  end
end
get("my_action.csv")

先前的行為是傳回 text/csv 回應的 Content-Type,這是不準確的,因為正在呈現 JSON 回應。目前的行為會正確傳回 application/json 回應的 Content-Type。

如果您的應用程式依賴先前的錯誤行為,建議您指定您的動作接受哪些格式,即

format.any(:xml, :json) { render request.format.to_sym => @people }

6.3 ActiveSupport::Callbacks#halted_callback_hook 現在會接收第二個引數

Active Support 允許您在回呼停止鏈時覆寫 halted_callback_hook。此方法現在會接收第二個引數,即正在停止的回呼名稱。如果您有類別覆寫此方法,請確保它接受兩個引數。請注意,這是一項重大變更,沒有先前的棄用週期(為了效能考量)。

範例

class Book < ApplicationRecord
  before_save { throw(:abort) }
  before_create { throw(:abort) }

  def halted_callback_hook(filter, callback_name) # => This method now accepts 2 arguments instead of 1
    Rails.logger.info("Book couldn't be #{callback_name}d")
  end
end

6.4 控制器中的 helper 類別方法使用 String#constantize

從概念上講,在 Rails 6.1 之前

helper "foo/bar"

導致

require_dependency "foo/bar_helper"
module_name = "foo/bar_helper".camelize
module_name.constantize

現在它會這樣做

prefix = "foo/bar".camelize
"#{prefix}Helper".constantize

此變更與大多數應用程式向後相容,在這種情況下,您不需要執行任何操作。

但是,從技術上講,控制器可以將 helpers_path 設定為指向 $LOAD_PATH 中不在自動載入路徑中的目錄。不再直接支援這種使用案例。如果 helper 模組不是可自動載入的,則應用程式負責在呼叫 helper 之前載入它。

6.5 從 HTTP 重新導向到 HTTPS 現在將使用 308 HTTP 狀態碼

當將非 GET/HEAD 請求從 HTTP 重新導向到 HTTPS 時,ActionDispatch::SSL 中使用的預設 HTTP 狀態碼已變更為 308,如 https://tools.ietf.org/html/rfc7538 中所定義。

6.6 Active Storage 現在需要 Image Processing

在 Active Storage 中處理變體時,現在必須捆綁 image_processing gem,而不是直接使用 mini_magick。預設情況下,Image Processing 已設定為在幕後使用 mini_magick,因此最簡單的升級方式是將 mini_magick gem 替換為 image_processing gem,並確保移除對 combine_options 的明確使用,因為不再需要它。

為了提高可讀性,您可能希望將原始的 resize 呼叫變更為 image_processing 巨集。例如,不要使用

video.preview(resize: "100x100")
video.preview(resize: "100x100>")
video.preview(resize: "100x100^")

您可以分別執行

video.preview(resize_to_fit: [100, 100])
video.preview(resize_to_limit: [100, 100])
video.preview(resize_to_fill: [100, 100])

6.7 新的 ActiveModel::Error 類別

錯誤現在是新的 ActiveModel::Error 類別的實例,並變更了 API。這些變更中的一些變更可能會根據您操作錯誤的方式擲回錯誤,而其他變更則會列印棄用警告,以便在 Rails 7.0 中修正。

有關此變更的更多資訊和有關 API 變更的詳細資訊,請參閱此 PR

7 從 Rails 5.2 升級到 Rails 6.0

有關 Rails 6.0 所做變更的更多資訊,請參閱發行說明

7.1 使用 Webpacker

Webpacker 是 Rails 6 的預設 JavaScript 編譯器。但是,如果您正在升級應用程式,則預設情況下不會啟用它。如果您想要使用 Webpacker,請將其包含在您的 Gemfile 中並安裝它

gem "webpacker"
$ bin/rails webpacker:install

7.2 強制 SSL

控制器上的 force_ssl 方法已棄用,將在 Rails 6.1 中移除。建議您啟用 config.force_ssl,以在您的應用程式中強制執行 HTTPS 連線。如果您需要從重新導向中豁免特定端點,您可以使用 config.ssl_options 來設定該行為。

7.3 目的和到期中繼資料現在會內嵌到已簽署和加密的 Cookie 中,以提高安全性

為了提高安全性,Rails 會將目的和到期中繼資料內嵌到加密或已簽署的 Cookie 值中。

然後,Rails 可以阻止嘗試複製 Cookie 的已簽署/加密值並將其用作另一個 Cookie 值的攻擊。

這種新的內嵌中繼資料使這些 Cookie 與 Rails 6.0 之前的版本不相容。

如果您需要讓 Rails 5.2 和更舊的版本讀取您的 Cookie,或者您仍在驗證您的 6.0 部署並且想要能夠回滾,請將 Rails.application.config.action_dispatch.use_cookies_with_metadata 設定為 false

7.4 所有 npm 套件都已移至 @rails 範圍

如果您先前透過 npm/yarn 載入任何 actioncableactivestoragerails-ujs 套件,您必須更新這些相依性的名稱,才能將它們升級到 6.0.0

actioncable   → @rails/actioncable
activestorage → @rails/activestorage
rails-ujs     → @rails/ujs

7.5 Action Cable JavaScript API 變更

Action Cable JavaScript 套件已從 CoffeeScript 轉換為 ES2015,我們現在會在 npm 發行版中發布原始程式碼。

此版本包含 Action Cable JavaScript API 可選部分的重大變更

  • WebSocket 配接器和記錄器配接器的設定已從 ActionCable 的屬性移至 ActionCable.adapters 的屬性。如果您正在設定這些配接器,您需要進行這些變更

    -    ActionCable.WebSocket = MyWebSocket
    +    ActionCable.adapters.WebSocket = MyWebSocket
    
    -    ActionCable.logger = myLogger
    +    ActionCable.adapters.logger = myLogger
    
  • ActionCable.startDebugging()ActionCable.stopDebugging() 方法已移除,並替換為屬性 ActionCable.logger.enabled。如果您正在使用這些方法,您需要進行這些變更

    -    ActionCable.startDebugging()
    +    ActionCable.logger.enabled = true
    
    -    ActionCable.stopDebugging()
    +    ActionCable.logger.enabled = false
    

7.6 ActionDispatch::Response#content_type 現在會傳回未修改的 Content-Type 標頭

先前,ActionDispatch::Response#content_type 的傳回值不包含 charset 部分。此行為已變更為也包含先前省略的 charset 部分。

如果您只需要 MIME 類型,請改用 ActionDispatch::Response#media_type

之前

resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16")
resp.content_type #=> "text/csv; header=present"

之後

resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16")
resp.content_type #=> "text/csv; header=present; charset=utf-16"
resp.media_type   #=> "text/csv"

7.7 新的 config.hosts 設定

Rails 現在有一個新的 config.hosts 設定,用於安全目的。此設定在開發中預設為 localhost。如果您在開發中使用其他網域,您需要像這樣允許它們

# config/environments/development.rb

config.hosts << "dev.myapp.com"
config.hosts << /[a-z0-9-]+\.myapp\.com/ # Optionally, regexp is allowed as well

對於其他環境,config.hosts 預設為空,這表示 Rails 完全不會驗證主機。您可以選擇性地新增它們,如果您想要在生產環境中驗證它。

7.8 自動載入

Rails 6 的預設設定

# config/application.rb

config.load_defaults 6.0

在 CRuby 上啟用 zeitwerk 自動載入模式。在該模式下,自動載入、重新載入和急切載入由 Zeitwerk 管理。

如果您正在使用先前 Rails 版本的預設值,您可以像這樣啟用 zeitwerk

# config/application.rb

config.autoloader = :zeitwerk

7.8.1 公開 API

一般而言,應用程式不需要直接使用 Zeitwerk 的 API。Rails 會根據現有的合約設定所有內容:config.autoload_pathsconfig.cache_classes 等。

雖然應用程式應該堅持使用該介面,但實際的 Zeitwerk 載入器物件可以像這樣存取

Rails.autoloaders.main

例如,如果您需要預先載入單表繼承 (STI) 類別或設定自訂 inflector,這可能會很方便。

7.8.2 專案結構

如果正在升級的應用程式正確自動載入,則專案結構應已大部分相容。

然而,classic 模式會從遺失的常數名稱(underscore)推斷檔案名稱,而 zeitwerk 模式則會從檔案名稱推斷常數名稱(camelize)。這些輔助方法並不總是互為反函數,尤其是在涉及縮寫時。例如,"FOO".underscore"foo",但 "foo".camelize"Foo",而不是 "FOO"

可以使用 zeitwerk:check 任務檢查相容性

$ bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!

7.8.3 require_dependency

所有已知的 require_dependency 使用案例都已消除,您應該在專案中搜尋並刪除它們。

如果您的應用程式使用單表繼承,請參閱「自動載入和重新載入常數(Zeitwerk 模式)」指南中的 單表繼承章節

7.8.4 類別和模組定義中的完整名稱

您現在可以在類別和模組定義中可靠地使用常數路徑

# Autoloading in this class' body matches Ruby semantics now.
class Admin::UsersController < ApplicationController
  # ...
end

需要注意的一個小陷阱是,根據執行順序,經典的自動載入器有時能夠在以下程式碼中自動載入 Foo::Wadus

class Foo::Bar
  Wadus
end

這與 Ruby 的語義不符,因為 Foo 不在巢狀結構中,而且在 zeitwerk 模式下完全無法運作。如果您發現這種邊緣案例,可以使用完整名稱 Foo::Wadus

class Foo::Bar
  Foo::Wadus
end

或將 Foo 加入巢狀結構

module Foo
  class Bar
    Wadus
  end
end

7.8.5 Concerns

您可以從標準結構自動載入和預先載入,例如

app/models
app/models/concerns

在這種情況下,app/models/concerns 被假設為根目錄(因為它屬於自動載入路徑),並且它會被忽略為命名空間。因此,app/models/concerns/foo.rb 應該定義 Foo,而不是 Concerns::Foo

Concerns:: 命名空間在經典的自動載入器中作為實作的副作用而運作,但它並非真正的預期行為。使用 Concerns:: 的應用程式需要重新命名這些類別和模組,才能在 zeitwerk 模式下執行。

7.8.6 在自動載入路徑中包含 app

某些專案希望像 app/api/base.rb 定義 API::Base,並將 app 加入自動載入路徑,以便在 classic 模式下完成此操作。由於 Rails 會自動將 app 的所有子目錄加入自動載入路徑,因此我們遇到了另一個巢狀根目錄的情況,因此該設定不再有效。這與我們上面解釋的 concerns 原則類似。

如果您想保留該結構,您需要在初始化器中從自動載入路徑中刪除該子目錄

ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/api")

7.8.7 自動載入的常數和明確的命名空間

如果命名空間定義在檔案中,如這裡的 Hotel

app/models/hotel.rb         # Defines Hotel.
app/models/hotel/pricing.rb # Defines Hotel::Pricing.

則必須使用 classmodule 關鍵字設定 Hotel 常數。例如

class Hotel
end

很好。

類似的替代方案

Hotel = Class.new

Hotel = Struct.new

將無法運作,找不到 Hotel::Pricing 等子物件。

此限制僅適用於明確的命名空間。未使用命名空間定義的類別和模組可以使用這些慣用語定義。

7.8.8 一個檔案,一個常數(在相同的頂層)

classic 模式下,您可以在相同的頂層定義多個常數,並將它們全部重新載入。例如,假設

# app/models/foo.rb

class Foo
end

class Bar
end

雖然無法自動載入 Bar,但自動載入 Foo 也會將 Bar 標記為已自動載入。在 zeitwerk 模式下則不然,您需要將 Bar 移動到自己的檔案 bar.rb 中。一個檔案,一個常數。

這僅適用於與上面範例中相同的頂層常數。內部類別和模組是可以的。例如,考慮

# app/models/foo.rb

class Foo
  class InnerClass
  end
end

如果應用程式重新載入 Foo,它也會重新載入 Foo::InnerClass

7.8.9 Spring 和 test 環境

如果程式碼有變更,Spring 會重新載入應用程式程式碼。在 test 環境中,您需要啟用重新載入才能使其運作

# config/environments/test.rb

config.cache_classes = false

否則您會收到此錯誤

reloading is disabled because config.cache_classes is true

7.8.10 Bootsnap

Bootsnap 應至少為 1.4.2 版。

除此之外,如果執行 Ruby 2.5,Bootsnap 需要停用 iseq 快取,因為解譯器中有一個錯誤。請確保在該情況下至少依賴 Bootsnap 1.4.4。

7.8.11 config.add_autoload_paths_to_load_path

為了向後相容,新的設定點 config.add_autoload_paths_to_load_path 預設為 true,但允許您選擇不將自動載入路徑加入 $LOAD_PATH

這在大多數應用程式中都是有意義的,因為您永遠不應該要求 app/models 中的檔案,例如,而且 Zeitwerk 內部只使用絕對檔案名稱。

透過選擇不使用,您可以最佳化 $LOAD_PATH 查閱(減少要檢查的目錄),並節省 Bootsnap 的工作和記憶體消耗,因為它不需要為這些目錄建立索引。

7.8.12 線程安全

在傳統模式中,常數自動載入不是線程安全的,儘管 Rails 已有鎖定機制,例如在啟用自動載入時使 Web 請求線程安全,這在開發環境中很常見。

常數自動載入在 zeitwerk 模式下是線程安全的。例如,您現在可以在由 runner 命令執行的多線程腳本中自動載入。

7.8.13 config.autoload_paths 中的萬用字元

請注意類似以下的設定

config.autoload_paths += Dir["#{config.root}/lib/**/"]

config.autoload_paths 的每個元素都應代表頂層命名空間 (Object),因此它們不能巢狀(上述說明的 concerns 目錄除外)。

要修正此問題,只需移除萬用字元

config.autoload_paths << "#{config.root}/lib"

7.8.14 預先載入和自動載入一致

classic 模式下,如果 app/models/foo.rb 定義了 Bar,您將無法自動載入該檔案,但預先載入將會有效,因為它會盲目地遞迴載入檔案。如果您先測試預先載入,可能會因為稍後自動載入而導致執行失敗,這可能會成為錯誤的根源。

zeitwerk 模式下,這兩種載入模式是一致的,它們在相同的檔案中會失敗並產生錯誤。

7.8.15 如何在 Rails 6 中使用經典的自動載入器

應用程式可以載入 Rails 6 預設值,並且仍然可以使用經典的自動載入器,方法是透過以下方式設定 config.autoloader

# config/application.rb

config.load_defaults 6.0
config.autoloader = :classic

當在 Rails 6 應用程式中使用經典自動載入器時,建議將開發環境中的 Web 伺服器和背景處理器的並行層級設定為 1,因為存在線程安全問題。

7.9 Active Storage 指派行為變更

使用 Rails 5.2 的預設設定,指派給以 has_many_attached 宣告的附件集合會附加新檔案

class User < ApplicationRecord
  has_many_attached :highlights
end

user.highlights.attach(filename: "funky.jpg")
user.highlights.count # => 1

blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg")
user.update!(highlights: [ blob ])

user.highlights.count # => 2
user.highlights.first.filename # => "funky.jpg"
user.highlights.second.filename # => "town.jpg"

使用 Rails 6.0 的預設設定,指派給附件集合會取代現有檔案,而不是附加到它們。這與指派給集合關聯時的 Active Record 行為相符

user.highlights.attach(filename: "funky.jpg")
user.highlights.count # => 1

blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg")
user.update!(highlights: [ blob ])

user.highlights.count # => 1
user.highlights.first.filename # => "town.jpg"

#attach 可用於新增附件,而無需移除現有的附件

blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg")
user.highlights.attach(blob)

user.highlights.count # => 2
user.highlights.first.filename # => "funky.jpg"
user.highlights.second.filename # => "town.jpg"

現有的應用程式可以透過將 config.active_storage.replace_on_assign_to_many 設定為 true 來選擇加入此新行為。舊行為將在 Rails 7.0 中被棄用,並在 Rails 7.1 中移除。

7.10 自訂例外處理應用程式

無效的 AcceptContent-Type 請求標頭現在會引發例外狀況。預設的 config.exceptions_app 會特別處理該錯誤並進行補償。自訂例外應用程式也需要處理該錯誤,否則此類請求會導致 Rails 使用回退例外應用程式,並傳回 500 Internal Server Error

8 從 Rails 5.1 升級到 Rails 5.2

如需更多關於 Rails 5.2 所做的變更的資訊,請參閱版本說明

8.1 Bootsnap

Rails 5.2 在新產生的應用程式 Gemfile中加入了 bootsnap gem。app:update 命令會在 boot.rb 中設定它。如果您想使用它,請將其加入 Gemfile

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

否則請變更 boot.rb 以不使用 bootsnap。

為了提高安全性,Rails 現在也會將到期資訊嵌入加密或簽名的 Cookie 值中。

這個新嵌入的資訊會使這些 Cookie 與舊於 5.2 的 Rails 版本不相容。

如果您需要 5.1 及更舊版本讀取您的 Cookie,或者您仍在驗證您的 5.2 部署,並且希望允許您回滾,請將 Rails.application.config.action_dispatch.use_authenticated_cookie_encryption 設定為 false

9 從 Rails 5.0 升級到 Rails 5.1

如需更多關於 Rails 5.1 所做的變更的資訊,請參閱版本說明

9.1 頂層 HashWithIndifferentAccess 已軟性棄用

如果您的應用程式使用頂層 HashWithIndifferentAccess 類別,您應該慢慢將程式碼移至改用 ActiveSupport::HashWithIndifferentAccess

這只是軟性棄用,這表示您的程式碼目前不會中斷,也不會顯示棄用警告,但此常數將在未來移除。

此外,如果您有相當舊的 YAML 文件,其中包含此類物件的傾印,您可能需要重新載入和傾印它們,以確保它們參照正確的常數,並且將來載入它們不會中斷。

9.2 application.secrets 現在會以符號形式載入所有鍵

如果您的應用程式在 config/secrets.yml 中儲存巢狀設定,則現在所有鍵都會以符號形式載入,因此應該變更使用字串的存取方式。

Rails.application.secrets[:smtp_settings]["address"]

Rails.application.secrets[:smtp_settings][:address]

9.3 移除了 render 中已棄用的 :text:nothing 支援

如果您的控制器使用 render :text,它們將不再有效。使用 text/plain MIME 類型呈現文字的新方法是使用 render :plain

同樣地,render :nothing 也被移除,您應該使用 head 方法來傳送僅包含標頭的回應。例如,head :ok 會傳送 200 回應,且沒有要呈現的主體。

9.4 移除了已棄用的 redirect_to :back 支援

在 Rails 5.0 中,redirect_to :back 已被棄用。在 Rails 5.1 中,它已被完全移除。

作為替代方案,請使用 redirect_back。務必注意 redirect_back 也會接受一個 fallback_location 選項,如果遺失 HTTP_REFERER,將會使用該選項。

redirect_back(fallback_location: root_path)

10 從 Rails 4.2 升級到 Rails 5.0

如需更多關於 Rails 5.0 所做的變更的資訊,請參閱版本說明

10.1 需要 Ruby 2.2.2+ 以上版本

從 Ruby on Rails 5.0 開始,僅支援 Ruby 2.2.2+ 以上版本。在繼續之前,請確保您使用的是 Ruby 2.2.2 或更新版本。

10.2 Active Record 模型現在預設繼承自 ApplicationRecord

在 Rails 4.2 中,Active Record 模型會繼承自 ActiveRecord::Base。在 Rails 5.0 中,所有模型都會繼承自 ApplicationRecord

ApplicationRecord 是所有應用程式模型的新超類別,類似於應用程式控制器將 ApplicationController 子類別化,而不是 ActionController::Base。這為應用程式提供了單一位置來設定應用程式範圍的模型行為。

當從 Rails 4.2 升級到 Rails 5.0 時,您需要在 app/models/ 中建立一個 application_record.rb 檔案,並加入以下內容

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

然後確保您的所有模型都繼承自它。

10.3 透過 throw(:abort) 停止回呼鏈

在 Rails 4.2 中,當 'before' 回呼在 Active Record 和 Active Model 中傳回 false 時,整個回呼鏈會停止。換句話說,不會執行後續的 'before' 回呼,也不會執行包裝在回呼中的動作。

在 Rails 5.0 中,於 Active Record 或 Active Model 回呼中回傳 false 將不會產生中止回呼鏈的副作用。相反地,必須透過呼叫 throw(:abort) 來明確中止回呼鏈。

當您從 Rails 4.2 升級至 Rails 5.0 時,在這些回呼中回傳 false 仍會中止回呼鏈,但您會收到關於此即將變更的棄用警告。

當您準備好時,您可以選擇啟用新行為並移除棄用警告,方法是將以下設定加入您的 config/application.rb

ActiveSupport.halt_callback_chains_on_return_false = false

請注意,此選項不會影響 Active Support 回呼,因為當任何值回傳時,它們永遠不會中止鏈。

請參閱 #17227 以了解更多詳細資訊。

10.4 ActiveJob 現在預設繼承自 ApplicationJob

在 Rails 4.2 中,Active Job 繼承自 ActiveJob::Base。在 Rails 5.0 中,此行為已變更為現在繼承自 ApplicationJob

當從 Rails 4.2 升級至 Rails 5.0 時,您需要在 app/jobs/ 中建立一個 application_job.rb 檔案,並加入以下內容

class ApplicationJob < ActiveJob::Base
end

然後確保您所有的 Job 類別都繼承自它。

請參閱 #19034 以了解更多詳細資訊。

10.5 Rails 控制器測試

10.5.1 將一些輔助方法提取到 rails-controller-testing

assignsassert_template 已被提取到 rails-controller-testing gem 中。若要在您的控制器測試中繼續使用這些方法,請將 gem "rails-controller-testing" 加入您的 Gemfile

如果您使用 RSpec 進行測試,請參閱 gem 的說明文件中所需的額外設定。

10.5.2 上傳檔案時的新行為

如果您在測試中使用 ActionDispatch::Http::UploadedFile 來上傳檔案,您需要改為使用類似的 Rack::Test::UploadedFile 類別。

請參閱 #26404 以了解更多詳細資訊。

10.6 生產環境啟動後停用自動載入

預設情況下,在生產環境中啟動後,自動載入現在會停用。

應用程式的預先載入是啟動過程的一部分,因此頂層常數是沒問題的,並且仍然會自動載入,不需要要求它們的檔案。

在較深層次,僅在執行時執行的常數(例如一般方法主體)也是沒問題的,因為定義它們的檔案會在啟動時被預先載入。

對於絕大多數應用程式,此變更不需要任何動作。但在極少數情況下,您的應用程式在生產環境中執行時需要自動載入,請將 Rails.application.config.enable_dependency_loading 設定為 true。

10.7 XML 序列化

ActiveModel::Serializers::Xml 已從 Rails 提取到 activemodel-serializers-xml gem 中。若要在您的應用程式中繼續使用 XML 序列化,請將 gem "activemodel-serializers-xml" 加入您的 Gemfile

10.8 移除對舊版 mysql 資料庫介面的支援

Rails 5 移除對舊版 mysql 資料庫介面的支援。大多數使用者應該可以使用 mysql2 取代。當我們找到維護人員時,它將會轉換為單獨的 gem。

10.9 移除對 Debugger 的支援

Rails 5 要求的 Ruby 2.2 不支援 debugger。請改用 byebug

10.10 使用 bin/rails 執行任務和測試

Rails 5 增加了透過 bin/rails 而不是 rake 執行任務和測試的功能。一般來說,這些變更是與 rake 並行進行的,但有些已完全移植過來。

若要使用新的測試執行器,只需輸入 bin/rails test

rake dev:cache 現在是 bin/rails dev:cache

在您應用程式的根目錄內執行 bin/rails,以查看可用的命令清單。

10.11 ActionController::Parameters 不再繼承自 HashWithIndifferentAccess

在您的應用程式中呼叫 params 現在會回傳一個物件,而不是雜湊。如果您的參數已經被允許,則您不需要進行任何變更。如果您使用 map 和其他依賴於能夠讀取雜湊的方法,而不論 permitted? 為何,您都需要升級您的應用程式以先允許,然後再轉換為雜湊。

params.permit([:proceed_to, :return_to]).to_h

10.12 protect_from_forgery 現在預設為 prepend: false

protect_from_forgery 預設為 prepend: false,這表示它將被插入到您在應用程式中呼叫它的回呼鏈中的那個點。如果您希望 protect_from_forgery 始終先執行,則您應該將您的應用程式變更為使用 protect_from_forgery prepend: true

10.13 預設範本處理器現在是 RAW

副檔名中沒有範本處理器的檔案將使用 raw 處理器呈現。先前 Rails 會使用 ERB 範本處理器呈現檔案。

如果您不希望透過 raw 處理器處理您的檔案,您應該將一個可以被適當範本處理器剖析的副檔名加入您的檔案。

10.14 為範本相依性新增萬用字元比對

您現在可以為您的範本相依性使用萬用字元比對。例如,如果您將您的範本定義為如下所示

<% # Template Dependency: recordings/threads/events/subscribers_changed %>
<% # Template Dependency: recordings/threads/events/completed %>
<% # Template Dependency: recordings/threads/events/uncompleted %>

您現在只需使用萬用字元呼叫一次相依性。

<% # Template Dependency: recordings/threads/events/* %>

10.15 ActionView::Helpers::RecordTagHelper 移至外部 gem (record_tag_helper)

content_tag_fordiv_for 已被移除,改為僅使用 content_tag。若要繼續使用較舊的方法,請將 record_tag_helper gem 加入您的 Gemfile

gem "record_tag_helper", "~> 1.0"

請參閱 #18411 以了解更多詳細資訊。

10.16 移除對 protected_attributes Gem 的支援

Rails 5 不再支援 protected_attributes gem。

10.17 移除對 activerecord-deprecated_finders gem 的支援

Rails 5 不再支援 activerecord-deprecated_finders gem。

10.18 ActiveSupport::TestCase 預設測試順序現在是隨機的

當在您的應用程式中執行測試時,預設順序現在是 :random 而不是 :sorted。使用以下設定選項將其設定回 :sorted

# config/environments/test.rb
Rails.application.configure do
  config.active_support.test_order = :sorted
end

10.19 ActionController::Live 變成一個 Concern

如果您在包含在您的控制器中的另一個模組中包含 ActionController::Live,那麼您也應該使用 ActiveSupport::Concern 擴展該模組。或者,您可以使用 self.included hook 在 StreamingSupport 被包含後直接將 ActionController::Live 包含到控制器中。

這表示如果您的應用程式過去有自己的串流模組,則以下程式碼將在生產環境中中斷

# This is a work-around for streamed controllers performing authentication with Warden/Devise.
# See https://github.com/plataformatec/devise/issues/2332
# Authenticating in the router is another solution as suggested in that issue
class StreamingSupport
  include ActionController::Live # this won't work in production for Rails 5
  # extend ActiveSupport::Concern # unless you uncomment this line.

  def process(name)
    super(name)
  rescue ArgumentError => e
    if e.message == "uncaught throw :warden"
      throw :warden
    else
      raise e
    end
  end
end

10.20 新的框架預設值

10.20.1 Active Record belongs_to 預設為必要選項

如果關聯不存在,belongs_to 現在預設會觸發驗證錯誤。

可以使用 optional: true 針對每個關聯關閉此功能。

此預設值將在新應用程式中自動設定。如果現有的應用程式想要加入此功能,則需要在初始化程式中開啟它

config.active_record.belongs_to_required_by_default = true

預設情況下,設定適用於您所有模型的全域設定,但您可以針對每個模型覆蓋它。這應該有助於您將所有模型遷移為預設需要它們的關聯。

class Book < ApplicationRecord
  # model is not yet ready to have its association required by default

  self.belongs_to_required_by_default = false
  belongs_to(:author)
end

class Car < ApplicationRecord
  # model is ready to have its association required by default

  self.belongs_to_required_by_default = true
  belongs_to(:pilot)
end

10.20.2 每個表單的 CSRF 權杖

Rails 5 現在支援每個表單的 CSRF 權杖,以減輕使用 JavaScript 建立的表單的程式碼注入攻擊。啟用此選項後,您應用程式中的表單將各自擁有自己的 CSRF 權杖,該權杖特定於該表單的操作和方法。

config.action_controller.per_form_csrf_tokens = true

10.20.3 使用來源檢查的偽造保護

您現在可以將您的應用程式設定為檢查 HTTP Origin 標頭是否應該針對網站的來源進行檢查,作為額外的 CSRF 防禦。在您的設定中將以下內容設定為 true

config.action_controller.forgery_protection_origin_check = true

10.20.4 允許設定 Action Mailer 佇列名稱

預設的郵件程式佇列名稱是 mailers。此設定選項允許您全域變更佇列名稱。在您的設定中設定以下內容

config.action_mailer.deliver_later_queue_name = :new_queue_name

10.20.5 支援 Action Mailer 檢視中的片段快取

在您的設定中設定 config.action_mailer.perform_caching 以決定您的 Action Mailer 檢視是否應該支援快取。

config.action_mailer.perform_caching = true

10.20.6 設定 db:structure:dump 的輸出

如果您使用 schema_search_path 或其他 PostgreSQL 擴充功能,您可以控制如何傾印架構。設定為 :all 以產生所有傾印,或設定為 :schema_search_path 以從架構搜尋路徑產生。

config.active_record.dump_schemas = :all

10.20.7 設定 SSL 選項以啟用具有子網域的 HSTS

在您的設定中設定以下內容,以在使用子網域時啟用 HSTS

config.ssl_options = { hsts: { subdomains: true } }

10.20.8 保留接收者的時區

當使用 Ruby 2.4 時,您可以在呼叫 to_time 時保留接收者的時區。

ActiveSupport.to_time_preserves_timezone = false

10.21 JSON/JSONB 序列化的變更

在 Rails 5.0 中,JSON/JSONB 屬性的序列化和還原序列化方式已變更。現在,如果您將一個欄位設定為等於 String,Active Record 將不再將該字串轉換為 Hash,而是只會回傳字串。這不僅限於與模型互動的程式碼,也會影響 db/schema.rb 中的 :default 欄位設定。建議您不要將欄位設定為等於 String,而是傳遞 Hash,它會自動轉換為 JSON 字串並從中轉換。

11 從 Rails 4.1 升級到 Rails 4.2

11.1 Web Console

首先,在你的 Gemfile 中的 :development 群組加入 gem "web-console", "~> 2.0",並執行 bundle install(當你升級 Rails 時,它不會被包含進來)。安裝完成後,你只需在任何你想啟用的視圖中加入對 console helper 的引用(例如:<%= console %>)。此外,在開發環境中,任何你檢視的錯誤頁面也會提供一個 console。

11.2 Responders

respond_with 和類別層級的 respond_to 方法已被提取到 responders gem 中。要使用它們,只需在你的 Gemfile 中加入 gem "responders", "~> 2.0"。如果沒有在你的依賴項中包含 responders gem,則對 respond_withrespond_to 的調用(再次強調,是在類別層級)將不再有效。

# 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 不受影響,不需要額外的 gem。

# 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

更多詳細資訊請參閱 #16526

11.3 在 transaction 回呼中的錯誤處理

目前,Active Record 會抑制在 after_rollbackafter_commit 回呼中引發的錯誤,並只將它們列印到日誌中。在下一個版本中,這些錯誤將不再被抑制。相反地,這些錯誤會像其他 Active Record 回呼一樣正常傳播。

當你定義一個 after_rollbackafter_commit 回呼時,你將會收到一個關於這個即將到來的變更的棄用警告。當你準備好時,你可以選擇啟用新的行為,並透過在你的 config/application.rb 中加入以下配置來移除棄用警告:

config.active_record.raise_in_transactional_callbacks = true

更多詳細資訊請參閱 #14488#16537

11.4 測試案例的排序

在 Rails 5.0 中,測試案例預設會以隨機順序執行。為了預期此變更,Rails 4.2 引入了一個新的配置選項 active_support.test_order,用於明確指定測試排序。這允許你透過將選項設定為 :sorted 來鎖定目前的行為,或是透過將選項設定為 :random 來選擇未來行為。

如果你沒有為此選項指定值,則會發出一個棄用警告。為了避免這種情況,請在你的測試環境中加入以下行:

# config/environments/test.rb
Rails.application.configure do
  config.active_support.test_order = :sorted # or `:random` if you prefer
end

11.5 序列化屬性

當使用自訂編碼器(例如 serialize :metadata, JSON)時,將 nil 指派給序列化的屬性會將其以 NULL 儲存到資料庫中,而不是透過編碼器傳遞 nil 值(例如,當使用 JSON 編碼器時為 "null")。

11.6 生產環境日誌級別

在 Rails 5 中,生產環境的預設日誌級別將會從 :info 變更為 :debug。若要保留目前的預設值,請將以下行加入你的 production.rb 中:

# Set to `:info` to match the current default, or set to `:debug` to opt-into
# the future default.
config.log_level = :info

11.7 在 Rails 範本中的 after_bundle

如果你有一個 Rails 範本會將所有檔案加入版本控制,它會因為在 Bundler 之前執行而無法加入產生的 binstubs。

# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rake("db:migrate")

git :init
git add: "."
git commit: %Q{ -m 'Initial commit' }

你現在可以將 git 調用包裝在 after_bundle 區塊中。它會在 binstubs 產生後執行。

# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rake("db:migrate")

after_bundle do
  git :init
  git add: "."
  git commit: %Q{ -m 'Initial commit' }
end

11.8 Rails HTML Sanitizer

在你的應用程式中,對於清理 HTML 片段有了一個新的選擇。原先的 html-scanner 方法現在正式被棄用,改為使用 Rails HTML Sanitizer

這表示 sanitizesanitize_cssstrip_tagsstrip_links 方法由新的實作提供支援。

這個新的清理器內部使用 Loofah。Loofah 反過來使用 Nokogiri,它包裝了用 C 和 Java 編寫的 XML 解析器,因此無論你執行哪個 Ruby 版本,清理速度都應該更快。

新版本更新了 sanitize,因此它可以使用 Loofah::Scrubber 進行強大的清理。 在此處查看一些 scrubbers 的範例

還新增了兩個新的 scrubbers:PermitScrubberTargetScrubber。請閱讀 gem 的 readme 以取得更多資訊。

PermitScrubberTargetScrubber 的文件說明了你如何完全控制元素何時以及如何被移除。

如果你的應用程式需要使用舊的清理器實作,請在你的 Gemfile 中包含 rails-deprecated_sanitizer

gem "rails-deprecated_sanitizer"

11.9 Rails DOM 測試

TagAssertions 模組(包含諸如 assert_tag 之類的方法)已被棄用,改為使用 SelectorAssertions 模組中的 assert_select 方法,該模組已被提取到 rails-dom-testing gem 中。

11.10 遮罩的身份驗證令牌

為了減輕 SSL 攻擊,form_authenticity_token 現在被遮罩,使其每次請求都不同。因此,令牌會透過解除遮罩然後解密來驗證。因此,任何用於驗證來自非 Rails 表單的請求的策略,如果依賴靜態 session CSRF 令牌,就必須考慮到這一點。

11.11 Action Mailer

先前,在 mailer 類別上呼叫 mailer 方法會直接執行對應的實例方法。隨著 Active Job 和 #deliver_later 的引入,情況不再如此。在 Rails 4.2 中,實例方法的調用會被延遲到呼叫 deliver_nowdeliver_later 時。例如:

class Notifier < ActionMailer::Base
  def notify(user)
    puts "Called"
    mail(to: user.email)
  end
end
mail = Notifier.notify(user) # Notifier#notify is not yet called at this point
mail = mail.deliver_now           # Prints "Called"

這對大多數應用程式來說應該不會造成任何明顯的差異。但是,如果你需要同步執行某些非 mailer 方法,並且你先前依賴同步代理行為,則應該將它們直接定義為 mailer 類別上的類別方法。

class Notifier < ActionMailer::Base
  def self.broadcast_notifications(users, ...)
    users.each { |user| Notifier.notify(user, ...) }
  end
end

11.12 外鍵支援

遷移 DSL 已擴展為支援外鍵定義。如果你一直在使用 Foreigner gem,你可能需要考慮將其移除。請注意,Rails 的外鍵支援是 Foreigner 的子集。這表示並非每個 Foreigner 定義都可以完全由其 Rails 遷移 DSL 對應項取代。

遷移程序如下:

  1. Gemfile 中移除 gem "foreigner"
  2. 執行 bundle install
  3. 執行 bin/rake db:schema:dump
  4. 確保 db/schema.rb 包含每個外鍵定義及其必要的選項。

12 從 Rails 4.0 升級到 Rails 4.1

12.1 防止遠端 <script> 標籤的 CSRF 保護

或者,「哇!我的測試失敗了!!?」或「我的 <script> 小工具壞了!!」

跨網站請求偽造(CSRF)保護現在也涵蓋了具有 JavaScript 回應的 GET 請求。這可以防止第三方網站透過 <script> 標籤遠端引用你的 JavaScript 來提取敏感資料。

這表示你的功能和整合測試使用:

get :index, format: :js

現在將會觸發 CSRF 保護。切換到:

xhr :get, :index, format: :js

明確測試 XmlHttpRequest

你自己的 <script> 標籤也被視為跨來源,並且預設會被封鎖。如果你真的要從 <script> 標籤載入 JavaScript,你現在必須明確跳過這些動作的 CSRF 保護。

12.2 Spring

如果你想使用 Spring 作為你的應用程式預載器,你需要:

  1. gem "spring", group: :development 加入你的 Gemfile
  2. 使用 bundle install 安裝 spring。
  3. 使用 bundle exec spring binstub 產生 Spring binstub。

使用者定義的 rake tasks 預設會在 development 環境中執行。如果你希望它們在其他環境中執行,請查閱 Spring README

12.3 config/secrets.yml

如果你想使用新的 secrets.yml 約定來儲存你的應用程式機密,你需要:

  1. 在你的 config 資料夾中建立一個 secrets.yml 檔案,內容如下:

    development:
      secret_key_base:
    
    test:
      secret_key_base:
    
    production:
      secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
    
  2. 使用你現有在 secret_token.rb 初始化器中的 secret_key_base,為在生產環境中執行 Rails 應用程式的任何使用者設定 SECRET_KEY_BASE 環境變數。或者,你可以直接將現有的 secret_key_basesecret_token.rb 初始化器複製到 secrets.yml 中的 production 區段,替換 <%= ENV["SECRET_KEY_BASE"] %>

  3. 移除 secret_token.rb 初始化器。

  4. 使用 rake secretdevelopmenttest 區段產生新的金鑰。

  5. 重新啟動你的伺服器。

12.4 測試 helper 的變更

如果你的測試 helper 包含對 ActiveRecord::Migration.check_pending! 的呼叫,則可以將其移除。當你 require "rails/test_help" 時,檢查現在會自動完成,儘管在你的 helper 中保留此行不會有任何損害。

12.5 Cookie 序列化程式

在 Rails 4.1 之前建立的應用程式使用 Marshal 將 cookie 值序列化到簽署和加密的 cookie jar 中。如果你想在你的應用程式中使用新的基於 JSON 的格式,你可以加入一個初始化檔案,內容如下:

Rails.application.config.action_dispatch.cookies_serializer = :hybrid

這會將你現有的 Marshal 序列化 cookie 透明地遷移到新的基於 JSON 的格式。

當使用 :json:hybrid 序列化程式時,你應該注意並非所有的 Ruby 物件都可以序列化為 JSON。例如,DateTime 物件將會被序列化為字串,而 Hash 的鍵將會被字串化。

class CookiesController < ApplicationController
  def set_cookie
    cookies.encrypted[:expiration_date] = Date.tomorrow # => Thu, 20 Mar 2014
    redirect_to action: "read_cookie"
  end

  def read_cookie
    cookies.encrypted[:expiration_date] # => "2014-03-20"
  end
end

建議你只將簡單的資料(字串和數字)儲存在 cookies 中。如果你必須儲存複雜的物件,你將需要在後續請求中讀取值時手動處理轉換。

如果你使用 cookie session store,這也將適用於 sessionflash hash。

12.6 Flash 結構變更

Flash 訊息鍵會被標準化為字串。它們仍然可以使用符號或字串來存取。循環遍歷 flash 時將始終產生字串鍵。

flash["string"] = "a string"
flash[:symbol] = "a symbol"

# Rails < 4.1
flash.keys # => ["string", :symbol]

# Rails >= 4.1
flash.keys # => ["string", "symbol"]

請確保你將 Flash 訊息鍵與字串進行比較。

12.7 JSON 處理的變更

在 Rails 4.1 中,有幾個與 JSON 處理相關的主要變更。

12.7.1 移除 MultiJSON

MultiJSON 已達到其生命週期終點,並且已從 Rails 中移除。

如果你的應用程式目前直接依賴 MultiJSON,你有幾個選項:

  1. 將 'multi_json' 加入你的 Gemfile。請注意,這在未來可能不再有效。

  2. 改用 obj.to_jsonJSON.parse(str),避免使用 MultiJSON。

不要單純將 MultiJson.dumpMultiJson.load 替換成 JSON.dumpJSON.load。這些 JSON gem API 用於序列化和反序列化任意 Ruby 物件,通常是不安全的。

12.7.2 JSON gem 相容性

過去,Rails 在與 JSON gem 的相容性方面存在一些問題。在 Rails 應用程式中使用 JSON.generateJSON.dump 可能會產生意外的錯誤。

Rails 4.1 通過將其自身的編碼器與 JSON gem 隔離來修復了這些問題。JSON gem API 將像平常一樣運行,但它們將無法存取任何 Rails 特有的功能。例如

class FooBar
  def as_json(options = nil)
    { foo: "bar" }
  end
end
irb> FooBar.new.to_json
=> "{\"foo\":\"bar\"}"
irb> JSON.generate(FooBar.new, quirks_mode: true)
=> "\"#<FooBar:0x007fa80a481610>\""

12.7.3 新的 JSON 編碼器

Rails 4.1 中的 JSON 編碼器已重寫為利用 JSON gem。對於大多數應用程式來說,這應該是一個透明的更改。但是,作為重寫的一部分,以下功能已從編碼器中移除

  1. 循環資料結構偵測
  2. encode_json 掛鉤的支援
  3. BigDecimal 物件編碼為數字而不是字串的選項

如果您的應用程式依賴這些功能之一,您可以通過將 activesupport-json_encoder gem 添加到您的 Gemfile 來恢復它們。

12.7.4 Time 物件的 JSON 表示

具有時間組件(TimeDateTimeActiveSupport::TimeWithZone)的物件的 #as_json 現在預設返回毫秒精度。如果您需要保留沒有毫秒精度的舊行為,請在初始化程式中設定以下內容

ActiveSupport::JSON::Encoding.time_precision = 0

12.8 在內聯回呼區塊中使用 return

先前,Rails 允許內聯回呼區塊以這種方式使用 return

class ReadOnlyModel < ActiveRecord::Base
  before_save { return false } # BAD
end

此行為從未被有意支援。由於 ActiveSupport::Callbacks 內部機制的更改,Rails 4.1 中不再允許這樣做。在內聯回呼區塊中使用 return 語句會導致在執行回呼時引發 LocalJumpError

可以使用評估為返回值的重構方式來處理使用 return 的內聯回呼區塊

class ReadOnlyModel < ActiveRecord::Base
  before_save { false } # GOOD
end

或者,如果偏好使用 return,建議明確定義一個方法

class ReadOnlyModel < ActiveRecord::Base
  before_save :before_save_callback # GOOD

  private
    def before_save_callback
      false
    end
end

此變更適用於 Rails 中大多數使用回呼的地方,包括 Active Record 和 Active Model 回呼,以及 Action Controller 中的篩選器(例如 before_action)。

有關更多詳細資訊,請參閱此拉取請求

12.9 在 Active Record fixtures 中定義的方法

Rails 4.1 在單獨的上下文中評估每個 fixture 的 ERB,因此在一個 fixture 中定義的 helper 方法在其他 fixture 中將不可用。

在多個 fixture 中使用的 helper 方法應在 test_helper.rb 中新引入的 ActiveRecord::FixtureSet.context_class 中包含的模組上定義。

module FixtureFileHelpers
  def file_sha(path)
    OpenSSL::Digest::SHA256.hexdigest(File.read(Rails.root.join("test/fixtures", path)))
  end
end

ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers

12.10 I18n 強制執行可用的 locale

Rails 4.1 現在預設將 I18n 選項 enforce_available_locales 設定為 true。這表示它將確保所有傳遞給它的 locale 都必須在 available_locales 清單中宣告。

若要停用它(並允許 I18n 接受任何 locale 選項),請將以下設定添加到您的應用程式

config.i18n.enforce_available_locales = false

請注意,此選項是作為安全措施添加的,以確保使用者輸入不能用作 locale 資訊,除非它先前已知。因此,建議不要停用此選項,除非您有充分的理由這樣做。

12.11 在 Relation 上呼叫 Mutator 方法

Relation 不再具有像 #map!#delete_if 這樣的 mutator 方法。在使用這些方法之前,請通過呼叫 #to_a 將其轉換為 Array

它旨在防止在直接在 Relation 上呼叫 mutator 方法的程式碼中出現奇怪的錯誤和混淆。

# Instead of this
Author.where(name: "Hank Moody").compact!

# Now you have to do this
authors = Author.where(name: "Hank Moody").to_a
authors.compact!

12.12 預設範圍的變更

預設範圍不再被鏈式條件覆蓋。

在之前的版本中,當您在模型中定義 default_scope 時,它會被同一欄位中的鏈式條件覆蓋。現在它像任何其他範圍一樣合併。

之前

class User < ActiveRecord::Base
  default_scope { where state: "pending" }
  scope :active, -> { where state: "active" }
  scope :inactive, -> { where state: "inactive" }
end

User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'

User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'active'

User.where(state: "inactive")
# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'

之後

class User < ActiveRecord::Base
  default_scope { where state: "pending" }
  scope :active, -> { where state: "active" }
  scope :inactive, -> { where state: "inactive" }
end

User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'

User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'active'

User.where(state: "inactive")
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending' AND "users"."state" = 'inactive'

若要取得之前的行為,需要使用 unscopedunscoperewhereexcept 明確移除 default_scope 條件。

class User < ActiveRecord::Base
  default_scope { where state: "pending" }
  scope :active, -> { unscope(where: :state).where(state: "active") }
  scope :inactive, -> { rewhere state: "inactive" }
end

User.all
# SELECT "users".* FROM "users" WHERE "users"."state" = 'pending'

User.active
# SELECT "users".* FROM "users" WHERE "users"."state" = 'active'

User.inactive
# SELECT "users".* FROM "users" WHERE "users"."state" = 'inactive'

12.13 從字串呈現內容

Rails 4.1 將 :plain:html:body 選項引入 render。這些選項現在是呈現基於字串的內容的首選方式,因為它允許您指定要以哪種內容類型傳送回應。

  • render :plain 會將內容類型設定為 text/plain
  • render :html 會將內容類型設定為 text/html
  • render :body設定內容類型標頭。

從安全角度來看,如果您不希望回應本文中包含任何標記,則應該使用 render :plain,因為大多數瀏覽器會為您轉義回應中的不安全內容。

我們將在未來版本中棄用 render :text 的使用。因此,請開始使用更精確的 :plain:html:body 選項。使用 render :text 可能會造成安全風險,因為內容是以 text/html 傳送的。

12.14 PostgreSQL JSON 和 hstore 資料類型

Rails 4.1 會將 jsonhstore 欄位對應到以字串為鍵的 Ruby Hash。在較早的版本中,使用 HashWithIndifferentAccess。這表示不再支援符號存取。基於 jsonhstore 欄位的 store_accessors 也是如此。請務必一致地使用字串鍵。

12.15 明確區塊使用於 ActiveSupport::Callbacks

Rails 4.1 現在要求在呼叫 ActiveSupport::Callbacks.set_callback 時傳遞明確的區塊。此變更源於 ActiveSupport::Callbacks 為 4.1 版本進行了大幅重寫。

# Previously in Rails 4.0
set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }

# Now in Rails 4.1
set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }

13 從 Rails 3.2 升級到 Rails 4.0

如果您的應用程式目前使用任何低於 3.2.x 的 Rails 版本,您應該先升級到 Rails 3.2,然後再嘗試升級到 Rails 4.0。

以下變更旨在將您的應用程式升級到 Rails 4.0。

13.1 HTTP PATCH

當在 config/routes.rb 中宣告 RESTful 資源時,Rails 4 現在使用 PATCH 作為更新的主要 HTTP 動詞。仍然使用 update 動作,並且 PUT 請求也將繼續路由到 update 動作。因此,如果您僅使用標準的 RESTful 路由,則無需進行任何更改

resources :users
<%= form_for @user do |f| %>
class UsersController < ApplicationController
  def update
    # No change needed; PATCH will be preferred, and PUT will still work.
  end
end

但是,如果您使用 form_for 更新資源並結合使用 PUT HTTP 方法的自訂路由,則需要進行更改

resources :users do
  put :update_name, on: :member
end
<%= form_for [ :update_name, @user ] do |f| %>
class UsersController < ApplicationController
  def update_name
    # Change needed; form_for will try to use a non-existent PATCH route.
  end
end

如果該動作未在公共 API 中使用,並且您可以自由更改 HTTP 方法,則可以更新路由以使用 patch 而不是 put

resources :users do
  patch :update_name, on: :member
end

Rails 4 中對 /users/:idPUT 請求會像今天一樣路由到 update。因此,如果您的 API 取得真正的 PUT 請求,它將會正常運作。路由器也會將對 /users/:idPATCH 請求路由到 update 動作。

如果該動作正在公共 API 中使用,並且您無法更改所使用的 HTTP 方法,則可以更新表單以使用 PUT 方法

<%= form_for [ :update_name, @user ], method: :put do |f| %>

有關 PATCH 以及為何進行此變更的更多資訊,請參閱 Rails 部落格上的這篇文章

13.1.1 關於媒體類型的注意事項

PATCH 動詞的勘誤指定應將「diff」媒體類型與 PATCH 一起使用。其中一種格式是JSON Patch。雖然 Rails 本身不支援 JSON Patch,但很容易新增支援

# in your controller:
def update
  respond_to do |format|
    format.json do
      # perform a partial update
      @article.update params[:article]
    end

    format.json_patch do
      # perform sophisticated change
    end
  end
end
# config/initializers/json_patch.rb
Mime::Type.register "application/json-patch+json", :json_patch

由於 JSON Patch 最近才被制定為 RFC,因此目前還沒有很多優秀的 Ruby 程式庫。Aaron Patterson 的 hana 就是這樣一個 gem,但它並不完全支援規格中的最後幾個變更。

13.2 Gemfile

Rails 4.0 從 Gemfile 中移除了 assets 群組。升級時您需要從 Gemfile 中移除該行。您還應該更新您的應用程式檔案 (在 config/application.rb 中)

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

13.3 vendor/plugins

Rails 4.0 不再支援從 vendor/plugins 載入外掛程式。您必須將外掛程式提取到 gem 並將其新增到 Gemfile 中來替換它們。如果您選擇不將它們變成 gem,您可以將它們移動到例如 lib/my_plugin/* 並在 config/initializers/my_plugin.rb 中新增適當的初始化程式。

13.4 Active Record

  • Rails 4.0 由於 與關聯的一些不一致,已從 Active Record 中移除了身分對應。如果您已在您的應用程式中手動啟用它,您將必須移除不再有效的以下設定: config.active_record.identity_map

  • 集合關聯中的 delete 方法現在可以接收 IntegerString 引數作為記錄 ID,以及記錄,幾乎與 destroy 方法一樣。先前,它會為此類引數引發 ActiveRecord::AssociationTypeMismatch。從 Rails 4.0 開始,delete 會在刪除記錄之前自動嘗試尋找與給定 ID 匹配的記錄。

  • 在 Rails 4.0 中,當欄位或表格被重新命名時,相關的索引也會被重新命名。如果您有重新命名索引的遷移,則不再需要它們。

  • Rails 4.0 已將 serialized_attributesattr_readonly 變更為僅限於類別方法。您不應該使用實例方法,因為它現在已棄用。您應該將它們變更為使用類別方法,例如 self.serialized_attributes 變更為 self.class.serialized_attributes

  • 當使用預設編碼器時,將 nil 指派給序列化的屬性會將其儲存到資料庫為 NULL,而不是通過 YAML 傳遞 nil 值("--- \n...\n")。

  • Rails 4.0 已刪除了 attr_accessibleattr_protected 功能,轉而使用 Strong Parameters。您可以使用 Protected Attributes gem 實現平穩的升級路徑。

  • 如果您沒有使用 Protected Attributes,則可以移除任何與此 gem 相關的選項,例如 whitelist_attributesmass_assignment_sanitizer 選項。

  • Rails 4.0 要求範圍使用可呼叫的物件,例如 Proc 或 lambda

    scope :active, where(active: true)
    
    # becomes
    scope :active, -> { where active: true }
    
  • Rails 4.0 已棄用 ActiveRecord::Fixtures,轉而使用 ActiveRecord::FixtureSet

  • Rails 4.0 已棄用 ActiveRecord::TestCase,轉而使用 ActiveSupport::TestCase

  • Rails 4.0 已棄用基於雜湊的舊樣式 finder API。這表示先前接受「finder 選項」的方法不再這樣做。例如,Book.find(:all, conditions: { name: '1984' }) 已被棄用,轉而使用 Book.where(name: '1984')

  • 除了 find_by_...find_by_...! 之外,所有動態方法都已棄用。以下是您可以處理這些變更的方式

    • find_all_by_... 變成 where(...)
    • find_last_by_... 變成 where(...).last
    • scoped_by_... 變成 where(...)
    • find_or_initialize_by_... 變成 find_or_initialize_by(...)
    • find_or_create_by_... 變成 find_or_create_by(...)
  • 請注意,where(...) 會返回關聯,而不是像舊的 finder 一樣返回陣列。如果您需要 Array,請使用 where(...).to_a

  • 這些等效的方法可能不會執行與先前實作相同的 SQL。

  • 若要重新啟用舊的 finder,您可以使用 activerecord-deprecated_finders gem

  • Rails 4.0 已將 has_and_belongs_to_many 關聯的預設聯結表格變更為剝離第二個表格名稱的常見前綴。任何具有常見前綴的模型之間的現有 has_and_belongs_to_many 關聯都必須使用 join_table 選項指定。例如

    class CatalogCategory < ActiveRecord::Base
      has_and_belongs_to_many :catalog_products, join_table: "catalog_categories_catalog_products"
    end
    
    class CatalogProduct < ActiveRecord::Base
      has_and_belongs_to_many :catalog_categories, join_table: "catalog_categories_catalog_products"
    end
    
  • 請注意,前綴也會考慮範圍,因此 Catalog::CategoryCatalog::ProductCatalog::CategoryCatalogProduct 之間的關聯也需要進行類似的更新。

13.5 Active Resource

Rails 4.0 將 Active Resource 提取成獨立的 gem。如果您仍然需要此功能,可以在您的 Gemfile 中加入 Active Resource gem

13.6 Active Model

  • Rails 4.0 變更了錯誤如何與 ActiveModel::Validations::ConfirmationValidator 連結的方式。現在,當確認驗證失敗時,錯誤會附加到 :#{attribute}_confirmation 而不是 attribute

  • Rails 4.0 將 ActiveModel::Serializers::JSON.include_root_in_json 的預設值變更為 false。現在,Active Model Serializers 和 Active Record 物件具有相同的預設行為。這表示您可以註解或移除 config/initializers/wrap_parameters.rb 檔案中的下列選項

    # Disable root element in JSON by default.
    # ActiveSupport.on_load(:active_record) do
    #   self.include_root_in_json = false
    # end
    

13.7 Action Pack

  • Rails 4.0 引入了 ActiveSupport::KeyGenerator,並以此作為產生和驗證簽名 Cookie(以及其他事項)的基礎。如果您保留現有的 secret_token 並加入新的 secret_key_base,則使用 Rails 3.x 產生的現有簽名 Cookie 將會被透明地升級。

    # config/initializers/secret_token.rb
    Myapp::Application.config.secret_token = "existing secret token"
    Myapp::Application.config.secret_key_base = "new secret key base"
    

    請注意,您應該等到 100% 的使用者都使用 Rails 4.x,並且相當確定您不需要回滾到 Rails 3.x 時,再設定 secret_key_base。這是因為基於 Rails 4.x 中新的 secret_key_base 簽名的 Cookie 與 Rails 3.x 不向後相容。您可以自由地保留現有的 secret_token,不設定新的 secret_key_base,並忽略棄用警告,直到您相當確定升級已完成為止。

    如果您依賴外部應用程式或 JavaScript 能夠讀取 Rails 應用程式的簽名 Session Cookie(或一般簽名 Cookie)的能力,您應該在解除這些問題的耦合之前,不要設定 secret_key_base

  • 如果設定了 secret_key_base,Rails 4.0 會加密基於 Cookie 的 Session 的內容。Rails 3.x 會簽名,但不會加密基於 Cookie 的 Session 的內容。簽名 Cookie 在驗證是由您的應用程式產生且防竄改方面是「安全的」。但是,終端使用者可以檢視內容,而加密內容可以消除這個顧慮,且不會造成顯著的效能損失。

    請閱讀 Pull Request #9978 以取得有關移至加密 Session Cookie 的詳細資訊。

  • Rails 4.0 移除了 ActionController::Base.asset_path 選項。請使用 assets pipeline 功能。

  • Rails 4.0 已棄用 ActionController::Base.page_cache_extension 選項。請改用 ActionController::Base.default_static_extension

  • Rails 4.0 已從 Action Pack 中移除 Action 和 Page 快取。您需要加入 actionpack-action_caching gem 才能在控制器中使用 caches_action,並加入 actionpack-page_caching 才能使用 caches_page

  • Rails 4.0 移除了 XML 參數解析器。如果您需要此功能,您需要加入 actionpack-xml_parser gem。

  • Rails 4.0 變更了使用符號或傳回 nil 的 Proc 來設定預設 layout 查找的方式。若要取得「無 Layout」的行為,請傳回 false 而不是 nil。

  • Rails 4.0 將預設的 memcached 用戶端從 memcache-client 變更為 dalli。若要升級,只需將 gem "dalli" 加入您的 Gemfile

  • Rails 4.0 棄用控制器中的 dom_iddom_class 方法(在 View 中仍可正常使用)。您需要在需要此功能的控制器中包含 ActionView::RecordIdentifier 模組。

  • Rails 4.0 棄用 link_to 輔助方法的 :confirm 選項。您應該改為依賴 data 屬性(例如 data: { confirm: 'Are you sure?' })。此棄用也與基於此輔助方法的其他輔助方法相關(例如 link_to_iflink_to_unless)。

  • Rails 4.0 變更了 assert_generatesassert_recognizesassert_routing 的運作方式。現在,所有這些斷言都會引發 Assertion 而不是 ActionController::RoutingError

  • 如果定義了衝突的具名路由,Rails 4.0 會引發 ArgumentError。這可以透過明確定義的具名路由或 resources 方法觸發。以下是兩個與名為 example_path 的路由衝突的範例

    get "one" => "test#example", as: :example
    get "two" => "test#example", as: :example
    
    resources :examples
    get "clashing/:id" => "test#example", as: :example
    

    在第一種情況下,您可以簡單地避免對多個路由使用相同的名稱。在第二種情況下,您可以使用 resources 方法提供的 onlyexcept 選項來限制建立的路由,如路由指南中所述。

  • Rails 4.0 也變更了繪製 Unicode 字元路由的方式。現在您可以直接繪製 Unicode 字元路由。如果您已經繪製了這類路由,您必須變更它們,例如

    get Rack::Utils.escape("こんにちは"), controller: "welcome", action: "index"
    

    變成

    get "こんにちは", controller: "welcome", action: "index"
    
  • 使用 match 的 Rails 4.0 路由必須指定請求方法。例如

    # Rails 3.x
    match "/" => "root#index"
    
    # becomes
    match "/" => "root#index", via: :get
    
    # or
    get "/" => "root#index"
    
  • Rails 4.0 已移除 ActionDispatch::BestStandardsSupport 中介軟體,<!DOCTYPE html> 已經根據 https://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx 觸發標準模式,而 ChromeFrame 標頭已移至 config.action_dispatch.default_headers

    請記住,您還必須從應用程式碼中移除對中介軟體的任何參考,例如

    # Raise exception
    config.middleware.insert_before(Rack::Lock, ActionDispatch::BestStandardsSupport)
    

    同時檢查您的環境設定是否有 config.action_dispatch.best_standards_support,如果存在則將其移除。

  • Rails 4.0 允許透過設定 config.action_dispatch.default_headers 來設定 HTTP 標頭。預設值如下

    config.action_dispatch.default_headers = {
      "X-Frame-Options" => "SAMEORIGIN",
      "X-XSS-Protection" => "1; mode=block"
    }
    

    請注意,如果您的應用程式依賴在 <frame><iframe> 中載入特定頁面,則您可能需要明確地將 X-Frame-Options 設定為 ALLOW-FROM ...ALLOWALL

  • 在 Rails 4.0 中,預編譯 Assets 不會再自動從 vendor/assetslib/assets 複製非 JS/CSS Assets。Rails 應用程式和引擎開發人員應該將這些 Assets 放入 app/assets 或設定 config.assets.precompile

  • 在 Rails 4.0 中,當 Action 無法處理請求格式時,會引發 ActionController::UnknownFormat。預設情況下,此例外會以回應 406 Not Acceptable 來處理,但您現在可以覆寫此例外。在 Rails 3 中,始終會傳回 406 Not Acceptable。沒有任何覆寫。

  • 在 Rails 4.0 中,當 ParamsParser 無法解析請求參數時,會引發泛型 ActionDispatch::ParamsParser::ParseError 例外。您會想要救援此例外,而不是低階的 MultiJson::DecodeError,例如。

  • 在 Rails 4.0 中,當引擎掛載在從 URL 前綴提供的應用程式上時,SCRIPT_NAME 會正確地巢狀化。您不再需要設定 default_url_options[:script_name] 來解決覆寫的 URL 前綴。

  • Rails 4.0 已棄用 ActionController::Integration,而改用 ActionDispatch::Integration

  • Rails 4.0 已棄用 ActionController::IntegrationTest,而改用 ActionDispatch::IntegrationTest

  • Rails 4.0 已棄用 ActionController::PerformanceTest,而改用 ActionDispatch::PerformanceTest

  • Rails 4.0 已棄用 ActionController::AbstractRequest,而改用 ActionDispatch::Request

  • Rails 4.0 已棄用 ActionController::Request,而改用 ActionDispatch::Request

  • Rails 4.0 已棄用 ActionController::AbstractResponse,而改用 ActionDispatch::Response

  • Rails 4.0 已棄用 ActionController::Response,而改用 ActionDispatch::Response

  • Rails 4.0 已棄用 ActionController::Routing,而改用 ActionDispatch::Routing

13.8 Active Support

Rails 4.0 移除了 ERB::Util#json_escapej 別名,因為 j 已用於 ActionView::Helpers::JavaScriptHelper#escape_javascript

13.8.1 快取

Rails 3.x 和 4.0 之間的快取方法有所變更。您應該變更快取命名空間,並使用冷快取進行部署。

13.9 輔助方法載入順序

在 Rails 4.0 中,從多個目錄載入輔助方法的順序已變更。先前,它們會被收集起來,然後按字母順序排序。升級到 Rails 4.0 後,輔助方法會保留已載入目錄的順序,並且只會在每個目錄內按字母順序排序。除非您明確使用 helpers_path 參數,否則此變更只會影響從引擎載入輔助方法的方式。如果您依賴排序,您應該檢查升級後是否可使用正確的方法。如果您想要變更載入引擎的順序,您可以使用 config.railties_order= 方法。

13.10 Active Record Observer 和 Action Controller Sweeper

ActiveRecord::ObserverActionController::Caching::Sweeper 已提取到 rails-observers gem。如果您需要這些功能,您需要加入 rails-observers gem。

13.11 sprockets-rails

  • assets:precompile:primaryassets:precompile:all 已移除。請改用 assets:precompile
  • config.assets.compress 選項應該變更為 config.assets.js_compressor,例如

    config.assets.js_compressor = :uglifier
    

13.12 sass-rails

  • 已棄用帶有兩個參數的 asset-url。例如:asset-url("rails.png", image) 變成 asset-url("rails.png")

14 從 Rails 3.1 升級到 Rails 3.2

如果您的應用程式目前使用任何低於 3.1.x 版本的 Rails,您應該先升級到 Rails 3.1,再嘗試更新到 Rails 3.2。

以下變更旨在將您的應用程式升級到最新 3.2.x 版本的 Rails。

14.1 Gemfile

請對您的 Gemfile 進行以下變更。

gem "rails", "3.2.21"

group :assets do
  gem "sass-rails",   "~> 3.2.6"
  gem "coffee-rails", "~> 3.2.2"
  gem "uglifier",     ">= 1.0.3"
end

14.2 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

14.3 config/environments/test.rb

mass_assignment_sanitizer 組態設定也應該加入 config/environments/test.rb

# Raise exception on mass assignment protection for Active Record models
config.active_record.mass_assignment_sanitizer = :strict

14.4 vendor/plugins

Rails 3.2 棄用 vendor/plugins,而 Rails 4.0 將完全移除它們。雖然這不是 Rails 3.2 升級的必要步驟,但您可以開始將任何外掛程式提取為 gem,並將其加入您的 Gemfile 來取代它們。如果您選擇不將它們設為 gem,您可以將它們移至例如 lib/my_plugin/*,並在 config/initializers/my_plugin.rb 中加入適當的初始化設定。

14.5 Active Record

已從 belongs_to 中移除選項 :dependent => :restrict。如果您想要防止在有任何關聯物件時刪除物件,您可以設定 :dependent => :destroy,並在從任何關聯物件的銷毀回呼檢查關聯是否存在後傳回 false

15 從 Rails 3.0 升級到 Rails 3.1

如果您的應用程式目前使用任何低於 3.0.x 版本的 Rails,您應該先升級到 Rails 3.0,再嘗試更新到 Rails 3.1。

以下變更旨在將您的應用程式升級到 Rails 3.1.12(Rails 的最後一個 3.1.x 版本)。

15.1 Gemfile

請對您的 Gemfile 進行以下變更。

gem "rails", "3.1.12"
gem "mysql2"

# Needed for the new asset pipeline
group :assets do
  gem "sass-rails",   "~> 3.1.7"
  gem "coffee-rails", "~> 3.1.1"
  gem "uglifier",     ">= 1.0.3"
end

# jQuery is the default JavaScript library in Rails 3.1
gem "jquery-rails"

15.2 config/application.rb

asset pipeline 需要以下新增內容

config.assets.enabled = true
config.assets.version = "1.0"

如果您的應用程式正在使用資源的 "/assets" 路由,您可能會想要變更用於 assets 的前綴,以避免衝突

# Defaults to '/assets'
config.assets.prefix = "/asset-files"

15.3 config/environments/development.rb

移除 RJS 設定 config.action_view.debug_rjs = true

如果您啟用 asset pipeline,請加入這些設定

# Do not compress assets
config.assets.compress = false

# Expands the lines which load the assets
config.assets.debug = true

15.4 config/environments/production.rb

同樣地,以下大部分變更都是針對 asset pipeline。您可以在Asset Pipeline 指南中閱讀更多相關資訊。

# Compress JavaScripts and CSS
config.assets.compress = true

# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false

# Generate digests for assets URLs
config.assets.digest = true

# Defaults to Rails.root.join("public/assets")
# config.assets.manifest = YOUR_PATH

# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
# config.assets.precompile += %w( admin.js admin.css )

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true

15.5 config/environments/test.rb

您可以透過對測試環境的這些新增內容來協助測試效能

# Configure static asset server for tests with Cache-Control for performance
config.public_file_server.enabled = true
config.public_file_server.headers = {
  "Cache-Control" => "public, max-age=3600"
}

15.6 config/initializers/wrap_parameters.rb

如果您想要將參數包裝到巢狀雜湊中,請新增此檔案並包含以下內容。這在新應用程式中預設為開啟。

# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.

# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
  wrap_parameters format: [:json]
end

# Disable root element in JSON by default.
ActiveSupport.on_load(:active_record) do
  self.include_root_in_json = false
end

15.7 config/initializers/session_store.rb

您需要將您的 Session 金鑰變更為新的金鑰,或移除所有 Session

# in config/initializers/session_store.rb
AppName::Application.config.session_store :cookie_store, key: "SOMETHINGNEW"

$ bin/rake db:sessions:clear

15.8 移除 View 中 asset 輔助方法參考中的 :cache 和 :concat 選項

  • 使用 Asset Pipeline 時,不再使用 :cache 和 :concat 選項,請從您的 View 中刪除這些選項。


回到頂端