v7.1.3.2
更多資訊請至 rubyonrails.org: 更多 Ruby on Rails

升級 Ruby on Rails

當您將應用程式升級到較新的 Ruby on Rails 版本時,本指南提供步驟供您遵循。這些步驟也出現在個別的版本指南中。

章節

  1. 一般建議
  2. 從 Rails 7.0 升級到 Rails 7.1
  3. 從 Rails 6.1 升級到 Rails 7.0
  4. 從 Rails 6.0 升級到 Rails 6.1
  5. 從 Rails 5.2 升級到 Rails 6.0
  6. 從 Rails 5.1 升級至 Rails 5.2
  7. 從 Rails 5.0 升級至 Rails 5.1
  8. 從 Rails 4.2 升級至 Rails 5.0
  9. 從 Rails 4.1 升級至 Rails 4.2
  10. 從 Rails 4.0 升級到 Rails 4.1
  11. 從 Rails 3.2 升級到 Rails 4.0
  12. 從 Rails 3.1 升級到 Rails 3.2
  13. 從 Rails 3.0 升級到 Rails 3.1

1 一般建議

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

1.1 測試涵蓋範圍

確保應用程式在升級後仍能正常運作的最佳方法,是在開始升級前先做好測試涵蓋率。如果您沒有自動化測試來執行應用程式的絕大部分,您需要花時間手動執行所有已變更的部分。對於 Rails 升級而言,這表示應用程式中的每個功能。在開始升級之前,請務必做好測試涵蓋率。

1.2 Ruby 版本

Rails 通常在最新發布的 Ruby 版本發布時緊跟其後

  • Rails 7 需要 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。主要和次要版本可以變更公開 API,因此這可能會導致應用程式發生錯誤。修補版本僅包含錯誤修正,不會變更任何公開 API。

流程應如下進行

  1. 撰寫測試並確保它們通過。
  2. 移至您目前版本之後的最新修補版本。
  3. 修正測試和已棄用的功能。
  4. 移至下一個次要版本的最新修補版本。

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

1.3.1 在版本之間移動

要在版本之間移動

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

您可以在 這裡 找到所有已發布 Rails 寶石的清單。

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_7_0.rb
...

別忘了檢視差異,看看是否有任何意外的變更。

1.5 設定架構預設值

新的 Rails 版本可能與前一個版本有不同的設定預設值。然而,在遵循上述步驟後,您的應用程式仍會使用前一個 Rails 版本的設定預設值執行。這是因為 config/application.rbconfig.load_defaults 的值尚未變更。

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

2 從 Rails 7.0 升級到 Rails 7.1

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

2.1 自動載入路徑不再位於 $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

2.2 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 中有 libconfig.autoload_lib_once 方法就是類似的

2.3 ActiveStorage::BaseController 不再包含串流問題

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

2.4 MemCacheStoreRedisCacheStore 現在預設使用連線池

connection_pool 這個 gem 已新增為 activesupport gem 的相依性,而 MemCacheStoreRedisCacheStore 現在預設使用連線池。

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

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

請參閱 使用 Rails 快取 指南以取得更多資訊。

2.5 SQLite3Adapter 現在已設定為在嚴格字串模式中使用

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

SQLite 在雙引號字串字面值方面有一些怪癖。它會先嘗試將雙引號字串視為識別名稱,但如果它們不存在,它就會將它們視為字串字面值。因此,錯字可能會靜默地不被發現。例如,有可能為不存在的欄位建立索引。請參閱 SQLite 文件 以取得更多詳細資訊。

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

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

2.6 為 ActionMailer::Preview 支援多個預覽路徑

選項 config.action_mailer.preview_path 已棄用,建議使用 config.action_mailer.preview_paths。將路徑附加到此組態選項會導致在搜尋郵件預覽時使用這些路徑。

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

2.7 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 或自訂例外處理常式。

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

透過 bin/rails test 執行測試時,rake test:prepare 任務會在測試執行前執行。如果您已強化 test:prepare 任務,您的強化功能會在測試前執行。tailwindcss-railsjsbundling-railscssbundling-rails 會強化此任務,其他第三方寶石也會強化此任務。

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

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

2.9 從 @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(...)

2.10 ActionView::TestCase#rendered 不再傳回 String

從 Rails 7.1 開始,ActionView::TestCase#rendered 傳回一個物件,它會回應各種格式方法(例如,rendered.htmlrendered.json)。為了保持向後相容性,從 rendered 傳回的物件會將遺失的方法委派給測試期間渲染的 String。例如,以下 assert_match 斷言將會通過

assert_match(/some content/i, rendered)

然而,如果您的測試依賴於 ActionView::TestCase#rendered 傳回 String 的執行個體,它們將會失敗。若要還原原始行為,您可以覆寫 #rendered 方法以從 @rendered 執行個體變數中讀取

# config/initializers/action_view.rb

ActiveSupport.on_load :action_view_test_case do
  attr_reader :rendered
end

2.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]

2.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 已被引入,以解決 一個錯誤,該錯誤導致某些屬性使用 SHA-1 加密,即使透過上述 hash_digest_class 設定設定了 SHA-256。

預設情況下,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

如果您正在處理加密資料,請仔細檢閱上述內容。

2.13 在控制器測試、整合測試和系統測試中處理例外的新方法

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)。

3 從 Rails 6.1 升級至 Rails 7.0

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

3.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)))

3.2 Spring

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

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

此外,請確定在 config/environments/test.rb 中將 config.cache_classes 設定為 false

3.3 Sprockets 現在是選用依賴項

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

gem "sprockets-rails"

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

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

3.5 設定器 config.autoloader= 已刪除

在 Rails 7 中,沒有設定點可以設定自動載入模式,config.autoloader= 已刪除。如果您因為某些原因將它設定為 :zeitwerk,請將它移除即可。

3.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 等。

3.7 初始化期間的自動載入

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

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

3.8 設定 config.autoload_once_paths 的能力

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

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

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

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

3.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

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

ActiveSupport::Digest 的預設摘要類別已從 SHA1 變更為 SHA256。這會影響 Etag 等會變更的項目,以及快取金鑰。變更這些金鑰可能會影響快取命中率,因此在升級到新的雜湊時請小心並注意這一點。

3.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 能夠讀取兩種格式,所以快取在升級期間不會失效。

3.13 Active Storage 影片預覽影像產生

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

3.14 Active Storage 預設變異處理器變更為 :vips

對於新的應用程式,影像轉換將使用 libvips,而非 ImageMagick。這將減少產生變異所需的時間,以及 CPU 和記憶體使用量,改善依賴 Active Storage 來提供其影像的應用程式的回應時間。

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

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

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

然後您需要將現有的影像轉換程式碼變更為 image_processing 巨集,並使用 libvips 的選項取代 ImageMagick 的選項。

3.14.1 使用 resize_to_limit 取代 resize

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

如果您沒有這樣做,當您切換到 vips 時,您會看到這個錯誤:無法將字串隱式轉換為浮點數

3.14.2 裁剪時使用陣列

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

如果您在移轉到 vips 時沒有這樣做,您會看到以下錯誤:無法呼叫裁剪:您提供了 2 個參數,但作業需要 5 個參數

3.14.3 限制您的裁剪值

在裁剪方面,Vips 比 ImageMagick 更加嚴格

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

如果您在移轉到 vips 時沒有執行此操作,您將會看到下列錯誤:extract_area: 錯誤的擷取區域

3.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]])

3.14.5 移出任何基於 EXIF 的旋轉

處理變體時,Vips 會使用 EXIF 值自動旋轉影像。如果您儲存從使用者上傳的照片的旋轉值以使用 ImageMagick 套用旋轉,您必須停止執行此操作

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

3.14.6 以色彩空間取代單色

Vips 使用不同的選項來製作單色影像

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

3.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 })

3.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 %>

3.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 傾印架構時,您會看到該檔案有許多變更,包括一些欄位資訊。請務必檢閱新的架構檔案內容,並提交至您的儲存庫。

4 從 Rails 6.0 升級至 Rails 6.1

如需有關對 Rails 6.1 所做變更的詳細資訊,請參閱 發行說明

4.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')

4.2 使用 respond_to#any 時的回應內容類型

回應中傳回的內容類型標頭可能與 Rails 6.0 傳回的內容類型不同,更具體地說,如果您的應用程式使用 respond_to { |format| format.any }。內容類型現在會根據指定的區塊,而非要求的格式為基礎。

範例

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

先前的行為會傳回 text/csv 回應的內容類型,這是不正確的,因為會呈現 JSON 回應。目前的行為會正確傳回 application/json 回應的內容類型。

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

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

4.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

控制器中的 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 之前載入它。

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

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

4.6 Active Storage 現在需要影像處理

在 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])

4.7 新的 ActiveModel::Error 類別

錯誤現在是新的 ActiveModel::Error 類別的執行個體,其中包含對 API 的變更。其中一些變更可能會擲出錯誤,具體取決於您如何處理錯誤,而其他變更會列印折舊警告,以便在 Rails 7.0 中修正。

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

5 從 Rails 5.2 升級至 Rails 6.0

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

5.1 使用 Webpacker

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

gem "webpacker"
$ bin/rails webpacker:install

5.2 強制 SSL

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

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

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

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

這個新的內嵌資料會讓這些 Cookie 與早於 6.0 的 Rails 版本不相容。

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

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

如果您先前透過 npm/yarn 載入任何 actioncableactivestoragerails-ujs 套件,您必須在將它們升級至 6.0.0 之前更新這些依賴項的名稱

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

5.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
    

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

先前,ActionDispatch::Response#content_type 的傳回值不包含字元集部分。此行為已變更,以包含先前遺漏的字元集部分。

如果您只需要 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"

5.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 根本不會驗證主機。如果您想要在生產環境中驗證主機,您可以選擇性地將它們加入。

5.8 自動載入

Rails 6 的預設組態

# config/application.rb

config.load_defaults 6.0

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

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

# config/application.rb

config.autoloader = :zeitwerk

5.8.1 公開 API

一般來說,應用程式不需要直接使用 Zeitwerk 的 API。Rails 會根據現有的合約設定好所有事情:config.autoload_pathsconfig.cache_classes 等。

雖然應用程式應該堅持使用該介面,但實際的 Zeitwerk 載入器物件可以透過以下方式存取

Rails.autoloaders.main

這在需要預載入單一資料表繼承 (STI) 類別或設定自訂的變形器時會很方便。

5.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!

5.8.3 require_dependency

require_dependency 的所有已知使用案例都已消除,您應該 grep 專案並將它們刪除。

如果您的應用程式使用單一資料表繼承,請參閱自動載入和重新載入常數 (Zeitwerk 模式) 指南的 單一資料表繼承區段

5.8.4 類別和模組定義中的限定名稱

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

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

需要注意的是,根據執行順序,傳統自動載入器有時能夠在

class Foo::Bar
  Wadus
end

自動載入 Foo::Wadus。這不符合 Ruby 語意,因為 Foo 不在巢狀結構中,而且在 zeitwerk 模式下根本無法使用。如果您發現這樣的邊界案例,可以使用限定名稱 Foo::Wadus

class Foo::Bar
  Foo::Wadus
end

或將 Foo 新增到巢狀結構中

module Foo
  class Bar
    Wadus
  end
end

5.8.5 疑慮

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

app/models
app/models/concerns

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

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

5.8.6 在自動載入路徑中擁有 app

有些專案希望類似 app/api/base.rb 來定義 API::Base,並將 app 新增到自動載入路徑中,以在 classic 模式中完成此操作。由於 Rails 會自動將 app 的所有子目錄新增到自動載入路徑中,因此我們有另一個情況,其中有巢狀根目錄,因此該設定不再有效。我們在上面說明的 concerns 原則類似。

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

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

5.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 這樣的子物件將找不到。

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

5.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

5.8.9 Spring 和 test 環境

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

# config/environments/test.rb

config.cache_classes = false

否則您會收到此錯誤

reloading is disabled because config.cache_classes is true

5.8.10 Bootsnap

Bootsnap 應至少為版本 1.4.2。

此外,如果執行 Ruby 2.5,Bootsnap 需要停用 iseq 快取,這是因為直譯器中的錯誤。請務必在這種情況下至少依賴 Bootsnap 1.4.4。

5.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 的工作和記憶體消耗,因為它不需要為這些目錄建立索引。

5.8.12 執行緒安全性

在經典模式中,常數自動載入並非執行緒安全,儘管 Rails 已設置鎖定,例如在啟用自動載入時,使 Web 要求執行緒安全,因為這在開發環境中很常見。

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

5.8.13 config.autoload_paths 中的 Glob

小心以下類型的組態

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

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

若要修正此問題,請移除萬用字元

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

5.8.14 急切載入和自動載入是一致的

classic 模式中,如果 app/models/foo.rb 定義 Bar,您將無法自動載入該檔案,但急切載入會運作,因為它會盲目地遞迴載入檔案。如果您先測試急切載入,執行緒可能會在稍後自動載入時失敗,這可能會造成錯誤的來源。

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

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

應用程式可以載入 Rails 6 預設值,並透過以下方式設定 config.autoloader 來繼續使用經典自動載入器

# config/application.rb

config.load_defaults 6.0
config.autoloader = :classic

在 Rails 6 應用程式中使用經典自動載入器時,建議在開發環境中將並行等級設定為 1,以適用於 Web 伺服器和背景處理程式,因為這涉及執行緒安全性問題。

5.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 中移除。

5.10 自訂例外處理應用程式

無效的 AcceptContent-Type 要求標頭現在會引發例外。預設的 config.exceptions_app 特別處理該錯誤並予以補償。自訂例外應用程式也需要處理該錯誤,否則此類要求將導致 Rails 使用後備例外應用程式,而後備例外應用程式會傳回 500 內部伺服器錯誤

6 從 Rails 5.1 升級至 Rails 5.2

如需有關對 Rails 5.2 所做變更的詳細資訊,請參閱 版本說明

6.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

7 從 Rails 5.0 升級到 Rails 5.1

有關對 Rails 5.1 進行的變更的更多資訊,請參閱 版本說明

7.1 頂層 HashWithIndifferentAccess 已軟棄用

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

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

此外,如果您有包含此類物件轉儲的非常舊的 YAML 文件,您可能需要再次載入和轉儲它們,以確保它們參照正確的常數,並且載入它們不會在未來中斷。

7.2 application.secrets 現在載入所有鍵為符號

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

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

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

7.3 已移除在 render 中對 :text:nothing 的已棄用支援

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

類似地,render :nothing 也已移除,您應使用 head 方法來傳送僅包含標頭的回應。例如,head :ok 傳送 200 回應,而沒有任何要呈現的本文。

7.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)

8 從 Rails 4.2 升級到 Rails 5.0

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

8.1 需要 Ruby 2.2.2+

從 Ruby on Rails 5.0 開始,Ruby 2.2.2+ 是唯一支援的 Ruby 版本。在繼續之前,請確定您使用的是 Ruby 2.2.2 版本或更高版本。

8.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

然後確定所有模型都繼承自它。

8.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 以取得更多詳細資料。

8.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

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

請參閱 #19034 以取得更多詳細資料。

8.5 Rails 控制器測試

8.5.1 將一些輔助方法萃取到 rails-controller-testing

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

如果您使用 RSpec 進行測試,請參閱寶石文件中的額外組態需求。

8.5.2 上傳檔案時的新行為

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

請參閱 #26404 以取得更多詳細資料。

8.6 在生產環境開機後停用自動載入

自動載入現在預設在生產環境開機後停用。

急切載入應用程式是開機程序的一部分,因此頂層常數沒問題,而且仍會自動載入,不需要載入它們的檔案。

在更深層的地方僅在執行時期執行的常數,例如常規方法主體,也沒問題,因為定義它們的檔案會在開機時急切載入。

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

8.7 XML 序列化

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

8.8 已移除對舊版 mysql 資料庫轉接器的支援

Rails 5 已移除對舊版 mysql 資料庫轉接器的支援。大多數使用者應可改用 mysql2。當我們找到維護者時,它將會轉換成一個獨立的 gem。

8.9 已移除對 Debugger 的支援

Rails 5 所需的 Ruby 2.2 不支援 debugger。請改用 byebug

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

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

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

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

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

8.11 ActionController::Parameters 不再繼承自 HashWithIndifferentAccess

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

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

8.12 protect_from_forgery 現在預設為 prepend: false

protect_from_forgery 預設為 prepend: false,表示它會在您在應用程式中呼叫它的點插入到回呼鏈中。如果您希望 protect_from_forgery 總是先執行,則您應該變更應用程式以使用 protect_from_forgery prepend: true

8.13 預設範本處理程式現在為 RAW

延伸元件中沒有範本處理程式的檔案將使用 raw 處理程式進行呈現。Rails 以前會使用 ERB 範本處理程式呈現檔案。

如果您不希望您的檔案透過 raw 處理程式處理,您應該為您的檔案新增一個延伸元件,適當的範本處理程式可以解析該延伸元件。

8.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/* %>

8.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 以取得更多詳細資料。

8.16 已移除對 protected_attributes Gem 的支援

protected_attributes gem 在 Rails 5 中不再受支援。

8.17 已移除對 activerecord-deprecated_finders gem 的支援

activerecord-deprecated_finders gem 在 Rails 5 中不再受支援。

8.18 ActiveSupport::TestCase 預設測試順序現在為隨機

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

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

8.19 ActionController::Live 已成為 Concern

如果您將 ActionController::Live 包含在控制器中包含的另一個模組中,則您也應該使用 ActiveSupport::Concern 來擴充模組。或者,您可以在 StreamingSupport 包含後,使用 self.included 鉤子將 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

8.20 新的架構預設值

8.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

8.20.2 每個表單的 CSRF 令牌

Rails 5 現在支援每個表單的 CSRF 令牌,以減輕 JavaScript 建立的表單中的程式碼注入攻擊。開啟此選項後,應用程式中的每個表單都會有自己的 CSRF 令牌,該令牌特定於該表單的動作和方法。

config.action_controller.per_form_csrf_tokens = true

8.20.3 使用來源檢查的偽造防護

您現在可以設定應用程式,檢查 HTTP Origin 標頭是否應該與網站來源比對,作為額外的 CSRF 防護。將設定中的下列項目設為 true

config.action_controller.forgery_protection_origin_check = true

8.20.4 允許設定 Action Mailer 佇列名稱

預設的郵件佇列名稱為 mailers。此設定選項允許您在全球變更佇列名稱。在您的設定中設定下列項目

config.action_mailer.deliver_later_queue_name = :new_queue_name

8.20.5 在 Action Mailer 檢視中支援片段快取

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

config.action_mailer.perform_caching = true

8.20.6 設定 db:structure:dump 的輸出

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

config.active_record.dump_schemas = :all

8.20.7 設定 SSL 選項以使用子網域啟用 HSTS

在設定中設定下列項目以在使用子網域時啟用 HSTS

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

8.20.8 保留接收者的時區

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

ActiveSupport.to_time_preserves_timezone = false

8.21 JSON/JSONB 序列化變更

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

9 從 Rails 4.1 升級到 Rails 4.2

9.1 網頁主控台

首先,將 gem 'web-console', '~> 2.0' 新增到 Gemfile 中的 :development 群組,並執行 bundle install(升級 Rails 時不會包含)。安裝後,只要在任何想要啟用它的檢視中,插入一個指向主控台輔助工具的參考(例如,<%= console %>)。在開發環境中檢視的任何錯誤頁面中,也會提供一個主控台。

9.2 回應器

respond_with 和類別層級的 respond_to 方法已被萃取到 responders gem。若要使用它們,只要將 gem 'responders', '~> 2.0' 新增到 Gemfile。在未將 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 以取得更多詳細資訊。

9.3 交易回呼中的錯誤處理

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

當您定義 after_rollbackafter_commit 回呼時,您會收到有關此即將到來的變更的棄用警告。準備好後,您可以選擇新的行為,並透過將下列設定新增到 config/application.rb 中,來移除棄用警告。

config.active_record.raise_in_transactional_callbacks = true

請參閱 #14488#16537 以取得更多詳細資訊。

9.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

9.5 序列化屬性

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

9.6 生產日誌層級

在 Rails 5 中,生產環境的預設日誌層級將變更為 :debug(從 :info 變更)。若要保留目前的預設值,請將下列程式碼行新增至您的 production.rb

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

9.7 Rails 範本中的 after_bundle

如果您有一個 Rails 範本會將所有檔案新增至版本控制,它會因為在 Bundler 之前執行而無法新增產生的 binstub。

# 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' }

您現在可以在 after_bundle 區塊中包裝 git 呼叫。它會在 binstub 產生後執行。

# 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

9.8 Rails HTML 清理器

現在有新的選擇可以清理應用程式中的 HTML 片段。備受推崇的 html-scanner 方法現已正式不建議使用,取而代之的是 Rails HTML Sanitizer

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

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

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

另外也新增了兩個 scrubber:PermitScrubberTargetScrubber。請閱讀 gem 的自述檔 以取得更多資訊。

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

如果您的應用程式需要使用舊的 sanitiser 實作,請在您的 Gemfile 中包含 rails-deprecated_sanitizer

gem 'rails-deprecated_sanitizer'

9.9 Rails DOM 測試

TagAssertions 模組(包含 assert_tag 等方法),已棄用,建議使用從 SelectorAssertions 模組中萃取出來的 assert_select 方法,此模組已萃取到 rails-dom-testing gem 中。

9.10 隱藏式真實性標記

為了減輕 SSL 攻擊,form_authenticity_token 現在已隱藏,因此它會隨著每個要求而有所不同。因此,標記會透過取消隱藏再解密來驗證。結果是,任何驗證來自非 Rails 表單要求的策略,如果依賴於靜態的 CSRF 會話標記,都必須考慮到這一點。

9.11 Action 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"

這不應對大多數應用程式造成任何明顯的差異。不過,如果您需要某些非郵件寄送器方法同步執行,而且您先前依賴於同步代理行為,您應將它們直接定義為郵件寄送器類別中的類別方法

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

9.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 包含每個外來鍵定義和必要的選項。

10 從 Rails 4.0 升級到 Rails 4.1

10.1 來自遠端 <script> 標籤的 CSRF 保護

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

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

這表示使用下列程式碼的功能和整合測試

get :index, format: :js

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

xhr :get, :index, format: :js

以明確測試 XmlHttpRequest

預設情況下,您的 <script> 標籤會被視為跨來源並遭到封鎖。如果您真的打算從 <script> 標籤載入 JavaScript,您現在必須在這些動作中明確略過 CSRF 保護。

10.2 Spring

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

  1. gem 'spring', group: :development 新增到您的 Gemfile
  2. 使用 bundle install 安裝 Spring。
  3. 使用 bundle exec spring binstub 產生 Spring binstub。

使用者定義的 rake 任務預設會在 development 環境中執行。如果您想要讓它們在其他環境中執行,請參閱 Spring README

10.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_key_basesecret_token.rb 初始化程式來設定 SECRET_KEY_BASE 環境變數,供在生產環境中執行 Rails 應用程式的使用者使用。或者,您也可以直接將現有的 secret_key_basesecret_token.rb 初始化程式複製到 secrets.yml 中的 production 區段,取代 <%= ENV["SECRET_KEY_BASE"] %>

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

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

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

10.4 測試輔助工具的變更

如果您的測試輔助工具包含對 ActiveRecord::Migration.check_pending! 的呼叫,則可以移除它。現在當您 require "rails/test_help" 時,檢查會自動執行,儘管將此行留在您的輔助工具中並不會造成任何危害。

10.5 Cookie 序列化器

在 Rails 4.1 之前建立的應用程式使用 Marshal 將 Cookie 值序列化成已簽署和加密的 Cookie 儲存區。如果您想在應用程式中使用新的基於 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

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

如果您使用 Cookie 會話儲存區,這也會套用於 sessionflash hash。

10.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 訊息金鑰與字串進行比較。

10.7 JSON 處理變更

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

10.7.1 MultiJSON 移 除

MultiJSON 已達 生命週期結束,並已從 Rails 中移除。

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

  1. 將 'multi_json' 加入您的 Gemfile。請注意,這在未來可能會停止運作

  2. 改用 obj.to_jsonJSON.parse(str) 來移轉 MultiJSON。

不要直接用 JSON.dumpJSON.load 取代 MultiJson.dumpMultiJson.load。這些 JSON gem API 是用於序列化和反序列化任意的 Ruby 物件,而且通常 不安全

10.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>\""

10.7.3 新的 JSON 編碼器

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

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

如果您的應用程式依賴其中一項功能,您可以透過將 activesupport-json_encoder gem 加入您的 Gemfile 來取回它們。

10.7.4 Time 物件的 JSON 表示

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

ActiveSupport::JSON::Encoding.time_precision = 0

10.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)。

請參閱 此合併請求 以取得更多詳細資料。

10.9 在 Active Record 固定裝置中定義的方法

Rails 4.1 在個別的內容中評估每個固定裝置的 ERB,因此在一個固定裝置中定義的輔助方法將不會在其他固定裝置中提供。

在多個固定裝置中使用到的輔助方法應該定義在 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

10.10 I18n 執行可用的語言環境

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

若要停用它(並允許 I18n 接受任何語言環境選項),請將下列組態新增至您的應用程式

config.i18n.enforce_available_locales = false

請注意,此選項已新增為安全措施,以確保使用者輸入無法用作地區資訊,除非先前已知。因此,建議不要停用此選項,除非你有充分的理由這麼做。

10.11 對 Relation 呼叫的變異方法

Relation 不再有變異方法,例如 #map!#delete_if。在使用這些方法之前,請透過呼叫 #to_a 轉換為 Array

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

# 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!

10.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'

10.13 從字串呈現內容

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

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

從安全性的角度來看,如果您不希望在回應主體中有任何標記,您應該使用 render :plain,因為大多數瀏覽器會為您跳脫回應中不安全的內容。

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

10.14 PostgreSQL JSON 和 hstore 資料類型

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

10.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 }

11 從 Rails 3.2 升級到 Rails 4.0

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

下列變更適用於將您的應用程式升級到 Rails 4.0。

11.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

PUT 對 Rails 4 中 /users/:id 的要求會導向 update,就像現在一樣。因此,如果您有一個會取得真實 PUT 要求的 API,它會運作。路由器也會將 PATCH 要求導向 /users/:idupdate 動作。

如果動作在公開 API 中使用,且您無法變更所使用的 HTTP 方法,您可以更新您的表單,改用 PUT 方法

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

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

11.1.1 關於媒體類型的說明

PATCH 動詞的勘誤表 指定應與 PATCH 一起使用「diff」媒體類型。其中一種格式是 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 就是其中一個寶石,但尚未完全支援規格中的最後幾項變更。

11.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)

11.3 vendor/plugins

Rails 4.0 不再支援從 vendor/plugins 載入外掛程式。您必須將所有外掛程式取代為寶石,並將它們新增至您的 Gemfile 中。如果您選擇不將它們設為寶石,您可以將它們移至,例如,lib/my_plugin/*,並在 config/initializers/my_plugin.rb 中新增適當的初始化程式。

11.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 功能,以支持強參數。您可以使用 Protected Attributes 範例 來順利升級。

  • 如果您沒有使用 Protected Attributes,您可以移除任何與此範例相關的選項,例如 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 已棄用舊式基於雜湊的查找器 API。這表示先前接受「查找器選項」的方法不再接受。例如,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(...) 會傳回關聯,而不是像舊版查找器傳回陣列。如果您需要 Array,請使用 where(...).to_a

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

  • 若要重新啟用舊版查找器,您可以使用 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 之間的關聯需要以類似的方式更新。

11.5 Active Resource

Rails 4.0 已將 Active Resource 萃取到其自己的 gem。如果您仍需要此功能,可以在 Gemfile 中新增 Active Resource gem

11.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
    

11.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 應用程式的簽署會話 Cookie(或一般的簽署 Cookie),則不應設定 secret_key_base,直到您解除這些疑慮為止。

  • 如果已設定 secret_key_base,Rails 4.0 會加密基於 Cookie 的會話內容。Rails 3.x 簽署了基於 Cookie 的會話內容,但未加密。簽署 Cookie「安全」,因為已驗證它們是由您的應用程式產生,且防竄改。然而,最終使用者可以檢視內容,而加密內容消除了這個疑慮/問題,且效能損失不大。

    請閱讀 Pull Request #9978,以取得有關移至加密會話 Cookie 的詳細資料。

  • Rails 4.0 已移除 ActionController::Base.asset_path 選項。請使用資產管線功能。

  • 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 的程序來尋找預設 layout。若要取得「無 layout」行為,請傳回 false,而非 nil。

  • Rails 4.0 將預設 memcached 伺服器端程式從 memcache-client 變更為 dalli。若要升級,請將 gem 'dalli' 新增到您的 Gemfile

  • Rails 4.0 棄用控制器中的 dom_iddom_class 方法(它們在檢視中是正常的)。您需要在需要此功能的控制器中包含 ActionView::RecordIdentifier 模組。

  • Rails 4.0 棄用 link_to 輔助工具的 :confirm 選項。您應該改用資料屬性(例如 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'
    
  • Rails 4.0 要求使用 match 的路由必須指定要求方法。例如

    # 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 中,預先編譯資產不再自動從 vendor/assetslib/assets 複製非 JS/CSS 資產。Rails 應用程式和引擎開發人員應將這些資產放入 app/assets 或設定 config.assets.precompile

  • 在 Rails 4.0 中,當動作不處理要求格式時,會引發 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

11.8 Active Support

Rails 4.0 已移除 j 別名,不再使用 ERB::Util#json_escape,因為 j 已用於 ActionView::Helpers::JavaScriptHelper#escape_javascript

11.8.1 Cache

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

11.9 Helpers 載入順序

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

11.10 Active Record Observer 和 Action Controller Sweeper

ActiveRecord::ObserverActionController::Caching::Sweeper 已移出到 rails-observers gem。如果您需要這些功能,您需要新增 rails-observers gem。

11.11 sprockets-rails

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

    config.assets.js_compressor = :uglifier
    

11.12 sass-rails

  • asset-url 使用兩個參數已過時。例如:asset-url("rails.png", image) 會變成 asset-url("rails.png")

12 從 Rails 3.1 升級到 Rails 3.2

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

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

12.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

12.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

12.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

12.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 中新增適當的初始化程式。

12.5 Active Record

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

13 從 Rails 3.0 升級到 Rails 3.1

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

以下變更適用於將您的應用程式升級到 Rails 3.1.12,也就是 Rails 的最後一個 3.1.x 版本。

13.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'

13.2 config/application.rb

資產管線需要以下新增項目

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

如果您的應用程式對資源使用「/assets」路由,您可能想要變更用於資產的前置詞,以避免衝突

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

13.3 config/environments/development.rb

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

如果您啟用資產管線,請新增這些設定

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

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

13.4 config/environments/production.rb

同樣地,以下大多數變更都適用於資產管線。您可以在 資產管線指南中進一步了解這些變更。

# 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

13.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'
}

13.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

13.7 config/initializers/session_store.rb

您需要將您的工作階段金鑰變更為新的金鑰,或移除所有工作階段

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

$ bin/rake db:sessions:clear

13.8 移除檢視中資產輔助程式參考中的 :cache 和 :concat 選項

  • 使用資產管線時,:cache 和 :concat 選項不再使用,請從您的檢視中刪除這些選項。

回饋

我們鼓勵您協助提升本指南的品質。

如果您發現任何錯字或事實錯誤,請協助我們修正。首先,您可以閱讀我們的 文件貢獻區段。

您也可能會發現不完整的內容或未更新的內容。請為 main 新增任何遺漏的文件。請務必先查看 Edge Guides,以驗證問題是否已在主分支中修復。查看 Ruby on Rails Guides Guidelines 以了解樣式和慣例。

如果由於任何原因,您發現需要修復但無法自行修補,請 開啟問題

最後但並非最不重要的一點,歡迎在 官方 Ruby on Rails 論壇 上進行任何有關 Ruby on Rails 文件的討論。