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。
該過程應如下進行:
- 編寫測試並確保它們通過。
- 移至當前版本之後的最新補丁版本。
- 修復測試和不推薦使用的功能。 4.移動到下一個次要版本的最新補丁版本。
重複此過程,直到達到目標 Rails 版本。
1.3.1 在版本之間移動
要在版本之間移動:
1.更改Gemfile
中的Rails版本號,執行bundle update
。
2. 更改 package.json
中 Rails JavaScript 包的版本並執行 yarn install
(如果在 Webpacker 上執行)。
3. 執行更新任務。
4. 執行您的測試。
您可以在 此處 中找到所有已釋出的 Rails 寶石的列表。
1.4 更新任務
Rails 提供了 rails app:update
命令。更新Rails版本後
在 Gemfile
中,執行此命令。
這將幫助您建立新檔案和更改舊檔案
互動式session。
$ 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
...
別忘了 review 的差異,看看有沒有什麼意想不到的變化。
1.5 設定框架預設值
新的 Rails 版本可能具有與以前版本不同的設定預設值。但是,在執行上述步驟後,您的應用程式仍將使用上一個 Rails 版本的設定預設值執行。這是因為 config/application.rb
中 config.load_defaults
的 value 尚未更改。
為了讓您一一升級到新的預設值,更新任務建立了一個檔案 config/initializers/new_framework_defaults_X.Y.rb
(檔名中包含所需的 Rails 版本)。您應該通過在檔案中取消註釋來啟用新的設定預設值;這可以通過多次部署逐步完成。一旦您的應用程式準備好以新的預設值執行,您可以刪除此檔案並翻轉 config.load_defaults
value。
2 從 Rails 6.1 升級到 Rails 7.0
2.1 彈簧
如果您的應用程式使用 Spring,則至少需要升級到 3.0.0 版本。否則你會得到
undefined method `mechanism=' for ActiveSupport::Dependencies:Module
另外,請確保在 config/environments/test.rb
中將 config.cache_classes
設定為 false
。
2.2 應用程式需要在 zeitwerk
模式下執行
仍在 classic
模式下執行的應用程式必須切換到 zeitwerk
模式。詳情請檢視Rails 6.0升級指南。
2.3 setter config.autoloader=
已刪除
Rails 7中沒有設定自動載入模式的設定點,刪除了config.autoloader=
。如果您出於某種原因將其設定為 :zeitwerk
,只需將其刪除即可。
2.4 ActiveSupport::Dependencies
私有API已刪除
ActiveSupport::Dependencies
的私有 API 已被刪除。這包括像 hook!
、unhook!
、depend_on
、require_or_load
、mechanism
等方法。
幾個亮點:
- 如果您使用
ActiveSupport::Dependencies.constantize
或 `ActiveSupport::Dependencies.safe_constantize
, just change them toString#constantize
orString#safe_constantize
。
ActiveSupport::Dependencies.constantize("User") # NO LONGER POSSIBLE
"User".constantize # 👍
任何對
ActiveSupport::Dependencies.mechanism
、reader 或 writer 的使用都必須被相應地訪問config.cache_classes
替換。如果要跟蹤自動載入器的活動,
ActiveSupport::Dependencies.verbose=
不再可用,只需將Rails.autoloaders.log!
扔到config/application.rb
中即可。
輔助內部類或 modules 也沒有了,例如 ActiveSupport::Dependencies::Reference
、ActiveSupport::Dependencies::Blamable
等。
2.5 初始化期間自動載入
在 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
。
2.6 能夠設定 config.autoload_once_paths
config.autoload_once_paths
可以在 config/application.rb
中定義的應用程式類的主體中設定,也可以在 config/environments/*
中的環境設定中設定。
類似地,引擎可以在引擎類的類主體或環境設定中設定該集合。
之後,集合被凍結,您可以從這些路徑自動載入。特別是,您可以在初始化期間從那裡自動載入。它們由 Rails.autoloaders.once
自動載入器管理,它不會重新載入,只會自動載入/急切載入。
如果您在處理環境設定後設定了此設定並且正在獲取 FrozenError
,請移動程式碼。
2.7 ActionDispatch::Request#content_type
現在原樣返回 Content-Type 標頭。
以前, ActionDispatch::Request#content_type
返回的 value 不包含字符集部分。
此行為更改為返回的包含字符集部分的 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"
2.8 Key 產生器摘要類更改為使用 SHA256
key 產生器的預設摘要類正在從 SHA1 更改為 SHA256。 這會對 Rails 產生的任何加密訊息產生影響,包括 加密的 cookies。
為了能夠使用舊的摘要類讀取訊息,有必要 註冊一個旋轉器。
以下是加密的 cookies 的旋轉器示例。
Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies|
salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt
secret_key_base = Rails.application.secrets.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
secret = key_generator.generate_key(salt, key_len)
cookies.rotate :encrypted, secret
end
2.9 ActiveSupport 的摘要類::摘要更改為 SHA256
ActiveSupport::Digest 的預設摘要類從 SHA1 更改為 SHA256。 這會對 Etags 之類的東西產生影響,這些東西也會改變和快取 keys。 更改這些 keys 會影響快取命中率,所以要小心謹慎 為此,在升級到新雜湊時。
2.10 新的 ActiveSupport::Cache 序列化格式
引入了更快、更緊湊的序列化格式。
要啟用它,您必須設定 config.active_support.cache_format_version = 7.0
:
# 設定/應用程式.rb
config.load_defaults 6.1
config.active_support.cache_format_version = 7.0
或者乾脆:
# 設定/應用程式.rb
config.load_defaults 7.0
但是 Rails 6.1 應用程式無法讀取這種新的序列化格式,
所以為了確保無縫升級,您必須首先部署 Rails 7.0 升級
config.active_support.cache_format_version = 6.1
,然後只有一次全部 Rails
流程已更新您可以設定config.active_support.cache_format_version = 7.0
。
Rails 7.0 能夠讀取這兩種格式,因此快取不會在 升級。
2.11 ActiveStorage 視訊 preview 影象產生
視訊 preview 影象產生現在使用 FFmpeg 的場景變化檢測來產生 更有意義的 preview 影象。以前將使用視訊的第一幀 如果視訊從黑色淡入,就會導致問題。這種變化需要 FFmpeg v3.4+。
2.12 ActiveStorage 變體處理器更改為 :vips
影象轉換現在將使用 libvips 而不是 ImageMagick。這將減少 產生變體所需的時間以及 CPU 和記憶體使用率,從而改善回應 依賴 active storage 來提供影象的應用程式中的次數。
:mini_magick
選項沒有被棄用,所以可以繼續使用它。
遷移到 libvips 需要將現有的影象轉換程式碼更改為
image_processing
巨集,並用 libvips 的選項替換 ImageMagick 的選項。
2.12.1 用 resize_to_limit 替換 resize
- variant(resize: "100x")
+ variant(resize_to_limit: [100, nil])
如果你忘記這樣做,當你切換到vips時你會看到這個錯誤:no implicit conversion to float from string
。
2.12.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
。
2.12.3 夾住你的作物 values:
Vips 在裁剪方面比 ImageMagick 更嚴格:
1. 如果 x
和/或 y
為負 values,則不會裁剪。例如:[-10, -10, 100, 100]
2.如果位置(x
或y
)加上裁剪尺寸(width
,height
)大於影象,則不會裁剪。例如:一個 125x125 的影象和一個 [50, 50, 100, 100]
的裁剪
如果你忘記這樣做,當你切換到vips時你會看到這個錯誤:extract_area: bad extract area
2.12.4 調整resize和pad使用的背景色
Vips 使用黑色作為預設背景色 resize_and_pad
,而不是像 ImageMagick 那樣的白色。使用 background
選項修復該問題:
diff
- variant(resize_and_pad: [300, 300])
+ variant(resize_and_pad: [300, 300, background: [255]])
2.12.5 刪除任何根據 EXIF 的旋轉
Vips 將在處理變體時使用 EXIF 值自動旋轉影象。如果您從使用者上傳的照片中儲存旋轉 values 以使用 ImageMagick 應用旋轉,則必須停止這樣做:
diff
- variant(format: :jpg, rotate: rotation_value)
+ variant(format: :jpg)
2.12.6 用色彩空間替換單色
Vips 使用不同的選項來製作單色影象:
diff
- variant(monochrome: true)
+ variant(colourspace: "b-w")
2.12.7 切換到用於壓縮影象的 libvips 選項
JPEG格式
diff
- variant(strip: true, quality: 80, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB")
+ variant(saver: { strip: true, quality: 80, interlace: true })
PNG
diff
- variant(strip: true, quality: 75)
+ variant(saver: { strip: true, compression: 9 })
網路
diff
- 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 })
動圖
diff
- variant(layers: "Optimize")
+ variant(saver: { optimize_gif_frames: true, optimize_gif_transparency: true })
2.12.8 部署到生產
Active Storage 將必須執行的轉換列表編碼到影象的 url 中。 如果您的應用程式正在快取這些 url,則在您將新程式碼部署到生產環境後,您的影象將中斷。 因此,您必須手動使受影響的快取 keys 無效。
例如,如果您在 view 中有這樣的內容:
rhtml
<% @products.each do |product| %>
<% cache product do %>
<%= image_tag product.cover_photo.variant(resize: "200x") %>
<% end %>
<% end %>
您可以通過觸控產品或更改快取 key 來使快取無效:
rhtml
<% @products.each do |product| %>
<% cache ["v2", product] do %>
<%= image_tag product.cover_photo.variant(resize_to_limit: [200, nill]) %>
<% end %>
<% end %>
3 從 Rails 6.0 升級到 Rails 6.1
有關對 Rails 6.1 所做更改的更多資訊,請參閱 發行說明。
3.1 Rails.application.config_for
返回 value 不再支援使用字串 keys 進行訪問。
給定一個這樣的設定檔案:
# 設定/example.yml
development:
options:
key: value
Rails.application.config_for(:example).options
這用於返回一個雜湊,您可以在該雜湊上使用字串 keys 訪問 values。這在 6.0 中已被棄用,現在不再起作用。
如果您仍然想使用字串 keys 訪問 values,您可以在 config_for
的返回值上呼叫 with_indifferent_access
,例如:
Rails.application.config_for(:example).with_indifferent_access.dig('options', 'key')
3.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
回應的內容型別。
如果您的應用程式依賴於之前的錯誤行為,我們鼓勵您指定 您的 action 接受哪種格式,即
format.any(:xml, :json) { render request.format.to_sym => @people }
3.3 ActiveSupport::Callbacks#halted_callback_hook
現在接收第二個引數
Active Support 允許您在 callback 時覆蓋 halted_callback_hook
停止鏈條。此方法現在接收第二個引數,即被暫停的 callback 的名稱。
如果您有覆蓋此方法的類,請確保它接受兩個引數。請注意,這是一箇中斷
在沒有預先棄用週期的情況下更改(出於效能原因)。
例子:
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
3.4 controllers中的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
此更改向後相容大多數應用程式,在這種情況下,您無需執行任何操作。
但是,從技術上講,controllers 可以將 helpers_path
設定為指向 $LOAD_PATH
中不在自動載入路徑中的目錄。開箱即用不再支援該用例。如果 helper module 不可自動載入,則應用程式負責在呼叫 helper
之前載入它。
3.5 從 HTTP 重定向到 HTTPS 現在將使用 308 HTTP 狀態程式碼
將非 GET/HEAD 請求從 HTTP 重定向到 HTTPS 時,在 ActionDispatch::SSL
中使用的預設 HTTP 狀態程式碼已更改為 https://tools.ietf.org/html/rfc7538 中定義的 308
。
3.6 Active Storage 現在需要影象處理
在 Active Storage 中處理變體時,現在需要捆綁 image_processing gem 而不是直接使用 mini_magick
。影象處理預設設定為在幕後使用 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 從 Rails 5.2 升級到 Rails 6.0
有關對 Rails 6.0 所做更改的更多資訊,請參閱 發行說明。
4.1 使用 Webpacker
Webpacker 是 Rails 6 的預設 JavaScript 編譯器。但是如果您正在升級應用程式,則預設情況下不會啟用它。 如果您想使用 Webpacker,請將其包含在您的 Gemfile 中並安裝它:
gem "webpacker"
$ bin/rails webpacker:install
4.2 強制 SSL
controllers 上的 force_ssl
方法已被棄用,將在
Rails 6.1。鼓勵您啟用 config.force_ssl
以強制執行 HTTPS
整個應用程式的連線。如果您需要免除某些端點
從重定向,您可以使用 config.ssl_options
來設定該行為。
4.3 目的和到期元資料現在嵌入在簽名和加密的 cookies 中以提高安全性
為了提高安全性,Rails 將用途和到期元資料嵌入到加密或簽名的 cookies value 中。
Rails 然後可以阻止試圖複製簽名/加密的 value 的攻擊 一個 cookie 並將其用作另一個 cookie 的 value。
這個新的嵌入元資料使那些 cookies 與早於 6.0 的 Rails 版本不相容。
如果您需要 cookies 5.2 及更早版本讀取 cookies,或者您仍在驗證 6.0 部署並希望
能夠回滾設定
Rails.application.config.action_dispatch.use_cookies_with_metadata
到 false
。
4.4 所有 npm 包都移到了 @rails
作用域
如果您之前載入了 actioncable
、activestorage
中的任何一個,
或者 rails-ujs
包通過 npm/yarn,你必須更新這些的名字
將依賴項升級到 6.0.0
之前:
actioncable → @rails/actioncable
activestorage → @rails/activestorage
rails-ujs → @rails/ujs
4.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
4.6 ActionDispatch::Response#content_type
現在無需修改即可返回 Content-Type 標頭
以前, ActionDispatch::Response#content_type
的返回 value 不包含字符集部分。
此行為已更改為包括先前省略的字符集部分。
如果您只需要 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"
4.7 自動載入
Rails 6 預設設定
# 設定/應用程式.rb
config.load_defaults 6.0
在 CRuby 上啟用 zeitwerk
自動載入模式。在這種模式下,自動載入、重新載入和預先載入由 Zeitwerk 管理。
4.7.1 公共介面
一般來說,應用程式不需要直接使用 Zeitwerk 的 API。 Rails 根據現有合約進行設定:config.autoload_paths
、config.cache_classes
等。
雖然應用程式應該堅持該介面,但實際的 Zeitwerk 載入器物件可以作為
Rails.autoloaders.main
例如,如果您需要預載入單表繼承 (STI) 類或設定自定義變形器,這可能會很方便。
4.7.2 專案結構
如果正在升級的應用程式正確自動載入,則專案結構應該已經基本相容。
但是,classic
模式從缺少的常量名 (underscore
) 推斷檔名,而 zeitwerk
模式從檔名 (camelize
) 推斷常量名。這些 helpers 並不總是彼此相反,尤其是在涉及首字母縮略詞時。例如,"FOO".underscore
是 "foo"
,但 "foo".camelize
是 "Foo"
,而不是 "FOO"
。
可以使用 zeitwerk:check
任務檢查相容性:
$ bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!
4.7.3 require_dependency
require_dependency
的所有已知用例都已消除,您應該 grep 專案並刪除它們。
如果您的應用程式使用單表繼承,請參閱自動載入和重新載入常量(Zeitwerk 模式)指南的單表繼承部分。
4.7.4 類中的限定名稱和 module 定義
您現在可以在類和 module 定義中穩健地使用常量路徑:
# 這個類的主體中的自動載入現在匹配 Ruby 語義。
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
4.7.5 關注點
您可以從標準結構自動載入和預先載入,例如
app/models
app/models/concerns
在這種情況下,app/models/concerns
被假定為根目錄(因為它屬於自動載入路徑),並且它作為名稱空間被忽略。所以,app/models/concerns/foo.rb
應該定義 Foo
,而不是 Concerns::Foo
。
Concerns::
名稱空間與經典自動載入器一起作為實現的副作用,但這並不是真正的預期行為。使用 Concerns::
的應用程式需要重新命名這些類和 modules 才能在 zeitwerk
模式下執行。
4.7.6 在自動載入路徑中有 app
一些專案想要像 app/api/base.rb
這樣的東西來定義 API::Base
,並將 app
新增到自動載入路徑中以在 classic
模式下完成。由於Rails自動將app
的所有子目錄新增到自動載入路徑中,我們還有另一種情況,其中存在巢狀的根目錄,因此設定不再起作用。類似的原理我們在上面用 concerns
解釋過。
如果要保留該結構,則需要從初始化程式的自動載入路徑中刪除子目錄:
ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/api")
4.7.7 自動載入常量和顯式名稱空間
如果在檔案中定義了名稱空間,則此處為 Hotel
:
app/models/hotel.rb # Defines Hotel.
app/models/hotel/pricing.rb # Defines Hotel::Pricing.
必須使用 class
或 module
keywords 設定 Hotel
常量。例如:
class Hotel
end
很好。
替代品,如
Hotel = Class.new
或者
Hotel = Struct.new
不會工作,不會找到像 Hotel::Pricing
這樣的子物件。
此限制僅適用於顯式名稱空間。沒有定義名稱空間的類和 modules 可以使用這些習語來定義。
4.7.8 一個檔案,一個常量(在同一個頂層)
在 classic
模式下,您可以在技術上在同一頂級定義幾個常量,並重新載入它們。例如,給定
# app/models/foo.rb
class Foo
end
class Bar
end
雖然 Bar
無法自動載入,但自動載入 Foo
也會將 Bar
標記為自動載入。 zeitwerk
模式下不是這樣,需要將Bar
移動到自己的檔案bar.rb
中。一個檔案,一個常量。
這僅影響與上面示例中相同的頂層的常量。內部類和 modules 很好。例如,考慮
# app/models/foo.rb
class Foo
class InnerClass
end
end
如果應用程式重新載入 Foo
,它也會重新載入 Foo::InnerClass
。
4.7.9 Spring 和 test
環境
如果發生變化,Spring 會重新載入應用程式程式碼。在 test
環境中,您需要啟用重新載入才能正常工作:
# 設定/環境/test.rb
config.cache_classes = false
否則你會得到這個錯誤:
reloading is disabled because config.cache_classes is true
4.7.10 載入程式
Bootsnap 至少應為 1.4.2 版。
除此之外,如果執行 Ruby 2.5,由於直譯器中的錯誤,Bootsnap 需要禁用 iseq 快取。在這種情況下,請確保至少依賴 Bootsnap 1.4.4。
4.7.11 config.add_autoload_paths_to_load_path
新的設定點
config.add_autoload_paths_to_load_path
預設情況下為 true
以實現向後相容性,但允許您選擇退出將自動載入路徑新增到 $LOAD_PATH
。
這在大多數應用程式中是有意義的,因為您永遠不應該需要 app/models
中的檔案,例如,Zeitwerk 僅在內部使用絕對檔名。
通過選擇退出,您可以優化 $LOAD_PATH
查詢(要檢查的目錄更少),並節省 Bootsnap 工作和記憶體消耗,因為它不需要為這些目錄構建索引。
4.7.12 執行緒安全
在經典模式下,常量自動載入不是執行緒安全的,儘管 Rails 有鎖定,例如在啟用自動載入時使 Web 請求執行緒安全,因為它在開發環境中很常見。
恆定自動載入在 zeitwerk
模式下是執行緒安全的。例如,您現在可以在由 runner
命令執行的多執行緒指令碼中自動載入。
4.7.13 config.autoload_paths 中的 Glob
當心像這樣的設定
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths
的每個元素都應該代表頂級名稱空間(Object
),因此它們不能巢狀(除了上面解釋的 concerns
目錄)。
要解決此問題,只需刪除萬用字元:
config.autoload_paths << "#{config.root}/lib"
4.7.14 Eager 載入和自動載入是一致的
在 classic
模式下,如果 app/models/foo.rb
定義了 Bar
,您將無法自動載入該檔案,但快速載入會起作用,因為它會盲目地遞迴載入檔案。如果您首先測試急切載入,這可能是錯誤的來源,稍後執行可能會失敗自動載入。
在 zeitwerk
模式下,兩種載入模式是一致的,它們在同一個檔案中失敗和出錯。
4.7.15 如何在 Rails 6 中使用 Classic Autoloader
應用程式可以載入 Rails 6 個預設值,並通過以這種方式設定 config.autoloader
仍然使用經典的自動載入器:
# 設定/應用程式.rb
config.load_defaults 6.0
config.autoloader = :classic
在 Rails 6 應用程式中使用 Classic Autoloader 時,由於執行緒安全問題,建議在開發環境中將 Web 伺服器和後臺處理器的平行計算級別設定為 1。
4.8 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 的預設設定,分配給附件集合會替換現有檔案而不是附加到它們。這與分配給集合 association 時的 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 從 Rails 5.1 升級到 Rails 5.2
有關對 Rails 5.2 所做更改的更多資訊,請參閱 發行說明。
5.1 載入程式
Rails 5.2 在新產生的應用程式的 Gemfile 中添加了 bootsnap gem。
app:update
命令在 boot.rb
中設定它。如果你想使用它,然後將它新增到 Gemfile 中,
否則更改 boot.rb
以不使用引導快照。
5.2 簽名或加密 cookie 中的到期現在嵌入在 cookies values 中
為了提高安全性,Rails 現在也將到期資訊嵌入到加密或簽名的 cookies value 中。
這個新的嵌入資訊使那些 cookies 與早於 5.2 的 Rails 版本不相容。
如果您需要 5.1 及更早版本讀取 cookies,或者您仍在驗證 5.2 部署並希望
允許您回滾設定
Rails.application.config.action_dispatch.use_authenticated_cookie_encryption
到 false
。
6 從 Rails 5.0 升級到 Rails 5.1
有關對 Rails 5.1 所做更改的更多資訊,請參閱 發行說明。
6.1 頂級 HashWithIndifferentAccess
已軟棄用
如果您的應用程式使用頂級 HashWithIndifferentAccess
類,您
應該慢慢移動你的程式碼來代替使用 ActiveSupport::HashWithIndifferentAccess
。
它只是軟棄用,這意味著您的程式碼不會在 時刻,不會顯示棄用警告,但這個常量將是 將來刪除。
此外,如果您有包含此類物件轉儲的非常舊的 YAML 文件, 您可能需要再次載入和轉儲它們以確保它們引用 正確的常量,並且載入它們將來不會中斷。
6.2 application.secrets
現在載入了所有 keys 作為 symbols
如果您的應用程式將巢狀設定儲存在 config/secrets.yml
中,則所有 keys
現在載入為 symbols,因此應該更改使用字串的訪問。
從:
Rails.application.secrets[:smtp_settings]["address"]
到:
Rails.application.secrets[:smtp_settings][:address]
6.3 在 render
中刪除了對 :text
和 :nothing
的棄用支援
如果您的 controllers 正在使用 render :text
,它們將不再起作用。新方法
使用 text/plain
的 MIME 型別渲染文字的方法是使用 render :plain
。
同樣,render :nothing
也被刪除,你應該使用 head
方法
傳送僅包含標頭的回應。例如,head :ok
傳送一個
200 回應,沒有要呈現的正文。
6.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)
7 從 Rails 4.2 升級到 Rails 5.0
有關對 Rails 5.0 所做更改的更多資訊,請參閱 發行說明。
7.1 Ruby 2.2.2+ 需要
從 Ruby 到 Rails 5.0 以後,Ruby 2.2.2+ 是唯一支援的 Ruby 版本。 在繼續之前,請確保您使用的是 Ruby 2.2.2 版本或更高版本。
7.2 Active Record Models 現在預設繼承自 ApplicationRecord
在 Rails 4.2 中,一個 Active Record model 繼承自 ActiveRecord::Base
。在 Rails 5.0 中,
所有的 models 都繼承自 ApplicationRecord
。
ApplicationRecord
是所有 app models 的新超類,類似於 app
controllers 子類化 ApplicationController
而不是
ActionController::Base
。這為應用程式提供了一個設定應用程式範圍的單一位置
model 行為。
從Rails 4.2升級到Rails 5.0時,需要建立一個
在 app/models/
中的 application_record.rb
檔案並新增以下內容:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
然後確保您所有的 models 都繼承自它。
7.3 通過 throw(:abort)
停止 Callback 鏈
在 Rails 4.2 中,當“之前” callback 在 Active Record 中返回 false
時
和 Active Model,那麼整個 callback 鏈就停止了。換句話說,
連續的“之前” callbacks 不會被執行,並且 action 也不會被包裝
在 callbacks。
在 Rails 5.0 中,在 Active Record 或 Active Model callback 中返回 false
不會有停止 callback 鏈的副作用。相反,callback
鏈必須通過呼叫 throw(:abort)
顯式停止。
當您從 Rails 4.2 升級到 Rails 5.0 時,返回 false
的那種
callbacks 仍將停止回呼鏈,但您將收到棄用
警告即將發生的變化。
準備好後,您可以選擇加入新行為並刪除棄用
通過將以下設定新增到您的 config/application.rb
來警告:
ActiveSupport.halt_callback_chains_on_return_false = false
請注意,此選項不會影響 Active Support callbacks 因為它們從不 當返回任何 value 時停止鏈。
有關更多詳細資訊,請參閱 #17227。
7.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。
7.5 Rails Controller 測試
7.5.1 一些 helper 方法的 Extraction 到 rails-controller-testing
assigns
和 assert_template
已被提取到 rails-controller-testing
gem。到
繼續在 controller 測試中使用這些方法,將 gem 'rails-controller-testing'
新增到
您的 Gemfile
。
如果您使用 RSpec 進行測試,請參閱 gem 中所需的額外設定 文件。
7.5.2 上傳檔案時的新行為
如果您在測試中使用 ActionDispatch::Http::UploadedFile
上傳檔案,你需要改用類似的Rack::Test::UploadedFile
類代替。
有關更多詳細資訊,請參閱 #26404。
7.6 生產環境啟動後自動載入關閉
現在通過以下方式在生產環境中啟動後禁用自動載入 預設。
熱切載入應用程式是啟動過程的一部分,因此頂級 常量很好並且仍然會自動載入,不需要需要它們的檔案。
更深的地方的常量只在執行時執行,比如正常方法體, 也很好,因為定義它們的檔案將在啟動時預先載入。
對於絕大多數應用程式,此更改不需要 action。但在
您的應用程式在執行時需要自動載入的非常罕見的事件
生產,將 Rails.application.config.enable_dependency_loading
設定為 true。
7.7 XML 序列化
ActiveModel::Serializers::Xml
已經從 Rails 提取到 activemodel-serializers-xml
寶石。要繼續在您的應用程式中使用 XML 序列化,請新增 gem 'activemodel-serializers-xml'
到您的 Gemfile
。
7.8 刪除了對舊版 mysql
資料庫介面卡的支援
Rails 5 刪除了對舊版 mysql
資料庫介面卡的支援。大多數使用者應該能夠
使用 mysql2
代替。找人維護時會轉成單獨的gem
它。
7.9 刪除了對偵錯程式的支援
Ruby 2.2 不支援 debugger
,而 Rails 需要 Rails 5。請改用 byebug
。
7.10 使用 bin/rails
來執行任務和測試
Rails 5 增加了通過 bin/rails
而不是 rake 執行任務和測試的能力。一般來說
這些變化與 rake 並行,但有些被完全移植。
要使用新的測試執行器,只需輸入 bin/rails test
。
rake dev:cache
現在是 bin/rails dev:cache
。
在應用程式的根目錄中執行 bin/rails
以檢視可用命令列表。
7.11 ActionController::Parameters
不再繼承 HashWithIndifferentAccess
在您的應用程式中呼叫 params
現在將返回一個物件而不是雜湊。如果你的
引數已經被允許,那麼您將不需要進行任何更改。如果您使用 map
以及其他依賴於能夠讀取雜湊的方法,而不管 permitted?
你會
需要升級您的應用程式以首先允許然後轉換為雜湊。
params.permit([:proceed_to, :return_to]).to_h
7.12 protect_from_forgery
現在預設為 prepend: false
protect_from_forgery
預設為 prepend: false
這意味著它將被插入到
callback 鏈在您在應用程式中呼叫它的點。如果你想
protect_from_forgery
始終首先執行,然後您應該更改您的應用程式以使用
protect_from_forgery prepend: true
。
7.13 預設模板處理程式現在是 RAW
擴充套件中沒有模板處理程式的檔案將使用原始處理程式呈現。 以前 Rails 將使用 ERB 模板處理程式呈現檔案。
如果您不希望通過原始處理程式處理您的檔案,您應該新增一個副檔名 到可以由適當的模板處理程式解析的檔案。
7.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/* %>
7.15 ActionView::Helpers::RecordTagHelper
移動到外部 gem (record_tag_helper)
content_tag_for
和 div_for
已被刪除,以支援僅使用 content_tag
。要繼續使用舊方法,請將 record_tag_helper
gem 新增到您的 Gemfile
:
gem 'record_tag_helper', '~> 1.0'
有關更多詳細資訊,請參閱 #18411。
7.16 移除了對 protected_attributes
Gem 的支援
Rails 5 不再支援 protected_attributes
gem。
7.17 刪除了對 activerecord-deprecated_finders
gem 的支援
Rails 5 不再支援 activerecord-deprecated_finders
gem。
7.18 ActiveSupport::TestCase
預設測試訂單現在是隨機的
在您的應用程式中執行測試時,預設順序現在是 :random
而不是 :sorted
。使用以下設定選項將其設定回 :sorted
。
# 設定/環境/test.rb
Rails.application.configure do
config.active_support.test_order = :sorted
end
7.19 ActionController::Live
變成了 Concern
如果您在 controller 中包含的另一個 module 中包含 ActionController::Live
,那麼您
還應該使用 ActiveSupport::Concern
擴充套件 module。或者,您可以使用 self.included
掛載機制
一旦包含 StreamingSupport
,將 ActionController::Live
直接包含到 controller 中。
這意味著如果您的應用程式曾經有自己的流媒體 module,則以下程式碼 會在生產中中斷:
# 這是流式 controllers 使用 Warden/Devise 執行身份驗證的變通方法。
# 見 https://github.com/plataformatec/devise/issues/2332
# 在路由器中進行身份驗證是該問題中建議的另一種解決方案
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
7.20 新框架預設值
7.20.1 Active Record belongs_to
預設選項需要
如果 association 不存在,則 belongs_to
現在預設會觸發驗證錯誤。
這可以通過 optional: true
關閉 per-association。
此預設值將在新應用程式中自動設定。如果現有應用 要新增此功能,需要在初始化程式中開啟它:
config.active_record.belongs_to_required_by_default = true
預設情況下,您的所有 models 的設定都是全域性的,但您可以 在每個模型的基礎上覆蓋它。這應該可以幫助您遷移所有 models 以擁有它們 associations 預設需要。
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
7.20.2 執行表單 CSRF Tokens
Rails 5 現在支援 per-form CSRF tokens 以減輕使用表單的程式碼注入攻擊 由 JavaScript 建立。啟用此選項後,您的應用程式中的每個表單都會有自己的 自己的 CSRF token 特定於 action 和該表單的方法。
config.action_controller.per_form_csrf_tokens = true
7.20.3 帶有原產地檢查的偽造保護
您現在可以設定您的應用程式以檢查是否應檢查 HTTP Origin
標頭
反對站點的起源作為額外的 CSRF 防禦。在您的設定中設定以下內容
真的:
config.action_controller.forgery_protection_origin_check = true
7.20.4 允許設定 Action Mailer 佇列名稱
預設的郵件佇列名稱是 mailers
。此設定選項允許您全域性更改
佇列名稱。在您的設定中設定以下內容:
config.action_mailer.deliver_later_queue_name = :new_queue_name
7.20.5 支援 Action Mailer 中的片段快取 Views
在您的設定中設定 config.action_mailer.perform_caching
以確定您的 Action Mailer views
應該支援快取。
config.action_mailer.perform_caching = true
7.20.6 設定db:structure:dump
的輸出
如果您使用 schema_search_path
或其他 PostgreSQL 擴充套件,您可以控制架構的方式
傾倒。設定為 :all
以產生所有轉儲,或設定為 :schema_search_path
以從模式搜尋路徑產生。
config.active_record.dump_schemas = :all
7.20.7 設定 SSL 選項以啟用子域的 HSTS
在您的設定中設定以下內容以在使用子域時啟用 HSTS:
config.ssl_options = { hsts: { subdomains: true } }
7.20.8 保留接收者的時區
使用 Ruby 2.4 時,可以在呼叫 to_time
時保留接收者的時區。
ActiveSupport.to_time_preserves_timezone = false
7.21 JSON/JSONB 序列化的變化
在 Rails 5.0 中,JSON/JSONB 屬性的序列化和反序列化方式發生了變化。現在,如果
您設定的列等於 String
,Active Record 將不再轉動該字串
進入 Hash
,而只會返回字串。這不僅限於程式碼
與 models 互動,但也會影響 db/schema.rb
中的 :default
列設定。
建議您不要將列設定為等於 String
,而是傳遞一個 Hash
相反,它將自動與 JSON 字串相互轉換。
8 從 Rails 4.1 升級到 Rails 4.2
8.1 網路控制檯
首先,將 gem 'web-console', '~> 2.0'
新增到 Gemfile
中的 :development
組並執行 bundle install
(升級 Rails 時不會包含它)。安裝完成後,您可以簡單地將控制檯 helper(即 <%= console %>
)的引用放入要啟用它的任何 view 中。您在開發環境中的 view 的任何錯誤頁面上也會提供一個控制檯。
8.2 回應者
respond_with
和類級別的 respond_to
方法已提取到 responders
gem。要使用它們,只需將 gem 'responders', '~> 2.0'
新增到您的 Gemfile
。如果不將 responders
gem 包含在您的依賴項中,則對 respond_with
和 respond_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。
8.3 transaction 中的錯誤處理 callbacks
目前,Active Record 抑制引發的錯誤
在 after_rollback
或 after_commit
callbacks 內,只將它們列印到
日誌。在下一個版本中,這些錯誤將不再被抑制。
相反,錯誤會像其他 Active 一樣正常傳播
記錄 callbacks。
當您定義 after_rollback
或 after_commit
callback 時,您
將收到有關此即將發生的更改的棄用警告。什麼時候
你準備好了,你可以選擇加入新的行為並刪除
通過將以下設定新增到您的
config/application.rb
:
config.active_record.raise_in_transactional_callbacks = true
8.4 測試用例排序
在 Rails 5.0 中,預設情況下會以隨機順序執行測試用例。在
期待這個變化,Rails 4.2 引入了一個新的設定選項
active_support.test_order
用於明確指定測試順序。這
允許您通過將選項設定為鎖定當前行為
:sorted
,或者通過將選項設定為 :random
來選擇未來的行為。
如果您沒有為此選項指定 value,則會出現棄用警告 發出。為避免這種情況,請將以下行新增到您的測試環境中:
# 設定/環境/test.rb
Rails.application.configure do
config.active_support.test_order = :sorted # or `:random` if you prefer
end
8.5 序列化屬性
使用自定義編碼器(例如 serialize :metadata, JSON
)時,
將 nil
分配給序列化的屬性會將其儲存到資料庫中
作為 NULL
而不是通過編碼器傳遞 nil
value(例如 "null"
使用 JSON
編碼器時)。
8.6 生產日誌級別
Rails 5中,將更改生產環境的預設日誌級別
到 :debug
(從 :info
)。要保留當前預設值,請新增以下內容
線到您的 production.rb
:
# 設定為 `:info` 以匹配當前預設值,或設定為 `:debug` 以選擇加入
# 未來的預設值。
config.log_level = :info
8.7 after_bundle
在 Rails 模板中
如果您有一個在版本控制中新增所有檔案的 Rails 模板,它 新增產生的 binstub 失敗,因為它在 Bundler 之前執行:
# 模板.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
塊中。它將執行
在產生 binstub 之後。
# 模板.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
8.8 Rails HTML 消毒劑
清理應用程式中的 HTML 片段有了新的選擇。這
古老的 html-scanner 方法現在正式被棄用,以支援
Rails HTML Sanitizer
。
這意味著方法 sanitize
、sanitize_css
、strip_tags
和
strip_links
由一個新的實現支援。
這種新的消毒劑在內部使用 Loofah。絲瓜絡反過來使用 Nokogiri,它 包裝用 C 和 Java 編寫的 XML 解析器,因此清理應該更快 無論您執行哪個 Ruby 版本。
新版本更新了sanitize
,所以可以取一個Loofah::Scrubber
強力擦洗。
在此處檢視洗滌器的一些示例。
還添加了兩個新的洗滌器:PermitScrubber
和 TargetScrubber
。
閱讀 gem 的自述檔案 瞭解更多資訊。
PermitScrubber
和 TargetScrubber
的文件解釋了您如何
可以完全控制何時以及如何剝離元素。
如果您的應用程式需要使用舊的 sanitizer 實現,請在您的 Gemfile
中包含 rails-deprecated_sanitizer
:
gem 'rails-deprecated_sanitizer'
8.9 Rails DOM 測試
TagAssertions
module(包含諸如assert_tag
之類的方法),已棄用支援ZHTW_3_19_WTHZ_WTHZ_1_WTHZ_WTHZ_assert_tag
1_WTHZ方法中的assert_select
方法,其中ZHTW_3_1_ZHWTZ_WTHZ_1_WTHZ_WTHZ_1WTHWT_WTHZ_test_zh_THZWHTZ_test_zh_1_ZHWTWT_test_zh_TWZ_1_ZHWT_WTHZ_test_1
8.10 偽裝真實性 Tokens
為了減輕 SSL 攻擊,form_authenticity_token
現在被遮蔽,以便它隨每個請求而變化。因此,tokens 通過取消遮蔽然後解密來驗證。因此,任何用於驗證來自非 rails 表單且依賴於靜態 session CSRF 令牌的請求的策略都必須考慮到這一點。
8.11 Action Mailer
以前,在郵件程式類上呼叫郵件程式方法將導致
直接執行對應的實例方法。隨著引進
Active Job 和 #deliver_later
,這不再是真的。在 Rails 4.2 中,
實例方法的呼叫被推遲到 deliver_now
或
deliver_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
8.12 國外 Key 支援
migration DSL 已擴充套件為支援外部 key 定義。如果 您一直在使用 Foreigner gem,您可能需要考慮將其刪除。 注意 Rails 的外部 key 支援是 Foreigner 的子集。這意味著 並非每個 Foreigner 定義都可以完全替換為其 Rails migration DSL 對應。
migration 過程如下:
- 從
Gemfile
中刪除gem "foreigner"
。 - 執行
bundle install
。 - 執行
bin/rake db:schema:dump
。 - 確保
db/schema.rb
包含每個外部 key 定義 必要的選項。
9 從 Rails 4.0 升級到 Rails 4.1
9.1 遠端 <script>
標籤的 CSRF 保護
或者,“我的測試失敗了!!!?”或“我的 <script>
小部件被破壞了!!”
跨站點請求偽造 (CSRF) 保護現在包含 GET 請求
JavaScript 回應也是如此。這可以防止第三方站點遠端訪問
使用 <script>
標記引用您的 JavaScript 以提取敏感資料。
這意味著您使用的功能和整合測試
get :index, format: :js
現在將觸發 CSRF 保護。切換到
xhr :get, :index, format: :js
顯式測試 XmlHttpRequest
。
您自己的 <script>
標籤被視為跨源並被
預設也是。如果您真的想從 <script>
標籤載入 JavaScript,
您現在必須明確跳過那些 actions 上的 CSRF 保護。
9.2 彈簧
如果您想使用 Spring 作為您的應用程式預載入器,您需要:
- 將
gem 'spring', group: :development
新增到您的Gemfile
。 - 使用
bundle install
安裝彈簧。 - 使用
bundle exec spring binstub
產生 Spring binstub。
使用者定義的 rake 任務將在 development
環境中執行
預設。如果您希望它們在其他環境中執行,請參閱
Spring README。
9.3 config/secrets.yml
如果您想使用新的 secrets.yml
約定來儲存應用程式的
祕密,你需要:
-
在
config
資料夾中建立一個secrets.yml
檔案,內容如下:development: secret_key_base: test: secret_key_base: production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
使用來自
secret_token.rb
初始值設定項的現有secret_key_base
為執行該程式的任何使用者設定SECRET_KEY_BASE
環境變數 Rails 應用程式在生產中。或者,您可以簡單地複製現有的secret_key_base
從secret_token.rb
初始化器到secrets.yml
在production
部分下,替換<%= ENV["SECRET_KEY_BASE"] %>
。移除
secret_token.rb
初始值設定項。使用
rake secret
為development
和test
部分產生新的 keys。重新啟動您的伺服器。
9.4 更改以測試 helper
如果您的測試 helper 包含對
ActiveRecord::Migration.check_pending!
這個可以去掉。支票
現在當你 require "rails/test_help"
時自動完成,雖然
將此行留在您的 helper 中沒有任何危害。
9.5 Cookies 序列化器
Rails 4.1 之前建立的應用程式使用 Marshal
將 cookie values 序列化為
簽名和加密的 cookie 罐子。如果要使用新的根據 JSON
的格式
在您的應用程式中,您可以新增一個包含以下內容的初始化檔案:
Rails.application.config.action_dispatch.cookies_serializer = :hybrid
這會將您現有的 Marshal
序列化 cookies 透明地遷移到
新的根據 JSON
的格式。
使用 :json
或 :hybrid
序列化程式時,您應該注意並非所有
Ruby 物件可以序列化為 JSON。例如,Date
和 Time
物件
將被序列化為字串,並且 Hash
es 將其 keys 字串化。
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 中儲存簡單資料(字串和數字)。 如果必須儲存複雜的物件,則需要處理轉換 在後續請求中讀取 values 時手動。
如果您使用 cookie session 儲存,這將適用於 session
和
flash
雜湊也是如此。
9.6 Flash 結構變化
Flash 訊息 keys 是 標準化為字串。他們 仍然可以使用 symbols 或字串訪問。迴圈通過閃光燈 將始終產生字串 keys:
flash["string"] = "a string"
flash[:symbol] = "a symbol"
# Rails < 4.1
flash.keys # => ["string", :symbol]
# Rails >= 4.1
flash.keys # => ["string", "symbol"]
確保將 Flash 訊息 keys 與字串進行比較。
9.7 JSON 處理的變化
Rails 4.1 中有一些與 JSON 處理相關的重大更改。
9.7.1 MultiJSON 移除
MultiJSON 已達到其 end-of-life 並已從 Rails 中移除。
如果您的應用程式當前直接依賴 MultiJSON,您有幾個選擇:
將“multi_json”新增到您的
Gemfile
。請注意,這可能會在未來停止工作使用
obj.to_json
和JSON.parse(str)
從 MultiJSON 遷移。
不要簡單地將 MultiJson.dump
和 MultiJson.load
替換為
JSON.dump
和 JSON.load
。這些 JSON gem API 用於序列化和
反序列化任意 Ruby 物件,通常是 不安全的。
9.7.2 JSON gem 相容性
從歷史上看,Rails 與 JSON gem 存在一些相容性問題。使用
Rails 應用程式中的 JSON.generate
和 JSON.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>\""
9.7.3 新的 JSON 編碼器
Rails 4.1 中的 JSON 編碼器已被重寫以利用 JSON 寶石。對於大多數應用程式,這應該是一個透明的更改。然而,作為 在重寫的一部分中,以下功能已從編碼器中刪除:
1.迴圈資料結構檢測
2.支援encode_json
掛載機制
3. 將 BigDecimal
物件編碼為數字而不是字串的選項
如果您的應用程式依賴於這些功能之一,您可以通過
新增 activesupport-json_encoder
寶石到您的 Gemfile
。
9.7.4 Time 物件的 JSON 表示
#as_json
用於具有時間分量的物件(Time
、DateTime
、ActiveSupport::TimeWithZone
)
現在預設返回毫秒精度。如果您需要保持沒有毫秒的舊行為
精度,在初始化程式中設定以下內容:
ActiveSupport::JSON::Encoding.time_precision = 0
9.8 在內聯 callback 塊中使用 return
以前,Rails 允許內聯 callback 塊以這種方式使用 return
:
class ReadOnlyModel < ActiveRecord::Base
before_save { return false } # BAD
end
這種行為從未被有意支援。由於內部結構的變化
ActiveSupport::Callbacks
的,在 Rails 4.1 中不再允許。用一個
內聯 callback 塊中的 return
語句導致 LocalJumpError
執行 callback 時引發。
可以重構使用 return
的內聯 callback 塊以評估為
返回 value:
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
return false
end
end
此更改適用於 Rails 中使用 callbacks 的大多數地方,包括
Active Record 和 Active Model callbacks,以及 Action 中的過濾器
Controller(例如 before_action
)。
請參閱 此拉取請求 瞭解更多 細節。
9.9 定義在 Active Record 夾具中的方法
Rails 4.1 在單獨的上下文中評估每個裝置的 ERB,因此 helper 方法 在一個裝置中定義的在其他裝置中不可用。
多個夾具中使用的 Helper 方法應在 modules 上定義
包含在新引入的 ActiveRecord::FixtureSet.context_class
中,在
test_helper.rb
。
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
9.10 I18n 強制執行可用的語言環境
Rails 4.1 現在預設 I18n 選項 enforce_available_locales
為 true
。這
意味著它將確保傳遞給它的所有語言環境都必須在
available_locales
列表。
要禁用它(並允許 I18n 接受 any 語言環境選項),請新增以下內容 設定到您的應用程式:
config.i18n.enforce_available_locales = false
請注意,此選項是作為安全措施新增的,以確保使用者輸入 除非事先知道,否則不能用作區域設定資訊。所以, 除非您有充分的理由,否則建議不要禁用此選項 這樣做。
9.11 對 Relation 呼叫的 Mutator 方法
Relation
不再有像 #map!
和 #delete_if
這樣的修改器方法。兌換
在使用這些方法之前通過呼叫 #to_a
到 Array
。
它的目標在於防止呼叫 mutator 的程式碼中出現奇怪的錯誤和混淆
方法直接放在 Relation
上。
# 而不是這個
Author.where(name: 'Hank Moody').compact!
# 現在你必須這樣做
authors = Author.where(name: 'Hank Moody').to_a
authors.compact!
9.12 預設範圍的變化
預設範圍不再被連結條件覆蓋。
在以前的版本中,當您在 model 中定義 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'
要獲得以前的行為,需要明確刪除
default_scope
條件使用 unscoped
、unscope
、rewhere
或
except
。
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'
9.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
。
9.14 PostgreSQL json 和 hstore 資料型別
Rails 4.1 將 json
和 hstore
列對映到字串-keyed Ruby Hash
。
在早期版本中,使用了 HashWithIndifferentAccess
。這意味著
不再支援 symbol 訪問。這也適用於
store_accessors
根據 json
或 hstore
列的頂部。確保使用
字串 keys 一致。
9.15 ActiveSupport::Callbacks
的顯式塊使用
Rails 4.1 現在期望在呼叫時傳遞一個顯式塊
ActiveSupport::Callbacks.set_callback
。這種變化源於
ActiveSupport::Callbacks
在 4.1 版本中被大量重寫。
# 以前在 Rails 4.0
set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }
# 現在在 Rails 4.1
set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
10 從 Rails 3.2 升級到 Rails 4.0
如果您的應用程式當前在任何早於 3.2.x 的 Rails 版本上,您應該先升級到 Rails 3.2,然後再嘗試升級到 Rails 4.0。
以下更改的目標在於將您的應用程序升級到 Rails 4.0。
10.1 HTTP 補丁
Rails 4 現在使用 PATCH
作為 RESTful 更新的主要 HTTP 動詞
資源在 config/routes.rb
中宣告。 update
action 仍在使用,
並且 PUT
請求也將繼續路由到 update
action。
因此,如果您僅使用標準 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 中未使用 action 並且您可以自由更改
HTTP 方法,您可以更新您的路由以使用 patch
而不是 put
:
resources :users do
patch :update_name, on: :member
end
PUT
對 Rails 4 中的 /users/:id
的請求被路由到 update
,因為它們是
今天。因此,如果您有一個可以獲取真實 PUT 請求的 API,它就會起作用。
路由器還將 PATCH
請求路由到 /users/:id
到 update
action。
如果在公共 API 中使用 action 並且您無法更改為 HTTP 方法
正在使用,您可以更新表單以使用 PUT
方法:
<%= form_for [ :update_name, @user ], method: :put do |f| %>
有關 PATCH 的更多資訊以及進行此更改的原因,請參閱 這篇文章 在 Rails 部落格上。
10.1.1 關於媒體型別的說明
PATCH
動詞的勘誤表 指定'diff' 媒體型別應該是
與 PATCH
一起使用。一
這種格式是JSON Patch。而 Rails
本身不支援 JSON Patch,新增支援很容易:
# 在您的 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 庫還沒有。亞倫帕特森的 hana 就是這樣一種寶石,但沒有 完全支援規範中的最後幾個更改。
10.2 Gemfile
Rails 4.0 從 Gemfile
中刪除了 assets
組。你需要刪除它
升級時從 Gemfile
行。您還應該更新您的應用程式
檔案(在 config/application.rb
中):
# 需要 Gemfile 中列出的寶石,包括任何寶石
# 你只限於:test、:development 或:production。
Bundler.require(*Rails.groups)
10.3 供應商/外掛
Rails 4.0 不再支援從 vendor/plugins
載入外掛。您必須通過將它們提取到 gems 並將它們新增到您的 Gemfile
來替換任何外掛。如果您選擇不讓它們成為寶石,您可以將它們移動到 lib/my_plugin/*
中,並在 config/initializers/my_plugin.rb
中新增適當的初始化程式。
10.4 Active Record
Rails 4.0 已經從 Active Record 中刪除了身份對映,因為與 associations 的一些不一致。如果您已在應用程式中手動啟用它,則必須刪除以下不再起作用的設定:
config.active_record.identity_map
。associations 集合中的
delete
方法現在可以接收Integer
或String
引數作為記錄 ID,除了記錄之外,與destroy
方法非常相似。以前它為此類引數引發了ActiveRecord::AssociationTypeMismatch
。從 Rails 4.0 開始,delete
會在刪除之前自動嘗試查詢與給定 id 匹配的記錄。在 Rails 4.0 中,當列或表被重新命名時,相關索引也被重新命名。如果您有重新命名索引的 migrations,則不再需要它們。
Rails 4.0 已將
serialized_attributes
和attr_readonly
更改為僅類方法。您不應該使用實例方法,因為它現在已被棄用。您應該將它們更改為使用類方法,例如self.serialized_attributes
到self.class.serialized_attributes
。使用預設編碼器時,將
nil
分配給序列化屬性將儲存它 到資料庫作為NULL
而不是通過 YAML ("--- \n...\n"
) 傳遞nil
value。Rails 4.0 刪除了
attr_accessible
和attr_protected
功能,支援強引數。您可以使用 Protected Attributes gem 獲得平滑的升級路徑。如果您沒有使用受保護的屬性,您可以刪除任何相關的選項 這個 gem 如
whitelist_attributes
或mass_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
關係的預設連線表,以去除第二個表名的公共字首。必須使用join_table
選項指定 models 與公共字首之間的任何現有has_and_belongs_to_many
關係。例如:CatalogCategory < ActiveRecord::Base has_and_belongs_to_many :catalog_products, join_table: 'catalog_categories_catalog_products' end CatalogProduct < ActiveRecord::Base has_and_belongs_to_many :catalog_categories, join_table: 'catalog_categories_catalog_products' end
注意字首也考慮了作用域,所以
Catalog::Category
和Catalog::Product
或Catalog::Category
和CatalogProduct
之間的關係需要類似地更新。
10.5 活動資源
Rails 4.0 將 Active Resource 提取到自己的 gem 中。如果您仍然需要該功能,您可以在您的 Gemfile
中新增 Active Resource gem。
10.6 Active Model
Rails 4.0 改變了錯誤附加到
ActiveModel::Validations::ConfirmationValidator
的方式。現在,當確認驗證失敗時,錯誤將附加到:#{attribute}_confirmation
而不是attribute
。-
Rails 4.0 已將
ActiveModel::Serializers::JSON.include_root_in_json
預設 value 更改為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
10.7 Action Pack
-
Rails 4.0 引入了
ActiveSupport::KeyGenerator
並將其用作產生和驗證已簽名的 cookies(除其他外)的基礎。如果您保留現有的secret_token
並新增新的secret_key_base
,則使用 Rails 3.x 產生的現有簽名 cookies 將透明升級。# config/initializers/secret_token.rb Myapp::Application.config.secret_token = 'existing secret token' Myapp::Application.config.secret_key_base = 'new secret key base'
請注意,您應該等到 Rails 4.x 上擁有 100% 的使用者群併合理確定您不需要回滾到 Rails 3.x 時再設定
secret_key_base
。這是因為根據 Rails 4.x 中新的secret_key_base
簽名的 cookies 不向後相容 Rails 3.x。您可以隨意保留現有的secret_token
,而不是設定新的secret_key_base
,並忽略棄用警告,直到您有理由確定升級已完成。如果您依賴於外部應用程式或 JavaScript 能夠讀取 Rails 應用程式的已簽名 session cookies(或一般已簽名 cookies)的能力,則在解除這些問題之前不應設定
secret_key_base
。 -
如果設定了
secret_key_base
,Rails 4.0 會加密根據 cookie 的 sessions 的內容。 Rails 3.x 已簽名但未加密根據 cookie 的會話的內容。簽名的 cookies 是“安全的”,因為它們經過驗證是由您的應用程式產生的並且是防篡改的。但是,終端使用者可以對內容進行 viewed,並且對內容進行加密可以消除這種警告/擔憂,而不會顯著降低效能。請閱讀 Pull Request #9978 以瞭解有關遷移到加密 session cookies 的詳細資訊。
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 和頁面快取。您需要新增
actionpack-action_caching
gem 才能在 controllers 中使用caches_action
和actionpack-page_caching
以使用caches_page
。Rails 4.0 移除了 XML 引數解析器。如果您需要此功能,則需要新增
actionpack-xml_parser
gem。Rails 4.0 使用 symbols 或返回 nil 的過程更改了預設的
layout
查詢集。要獲得“無佈局”行為,請返回 false 而不是 nil。Rails 4.0 將預設的 memcached 客戶端從
memcache-client
更改為dalli
。要升級,只需將gem 'dalli'
新增到您的Gemfile
。Rails 4.0 棄用了 controllers 中的
dom_id
和dom_class
方法(它們在 views 中很好)。您需要在需要此功能的 controllers 中包含ActionView::RecordIdentifier
module。Rails 4.0 棄用了
link_to
helper 的:confirm
選項。你應該 而是依賴於資料屬性(例如data: { confirm: 'Are you sure?' }
)。 此棄用還涉及根據此的 helpers(例如link_to_if
或link_to_unless
)。Rails 4.0 改變了
assert_generates
、assert_recognizes
和assert_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
在第一種情況下,您可以簡單地避免對多個使用相同的名稱 路線。在第二種中,您可以使用提供的
only
或except
選項resources
方法來限制建立的路由,詳見 路由指南。 -
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/assets
和lib/assets
複製非 JS/CSS 資產。 Rails 應用和引擎開發者應該將這些資產放在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
。
10.8 Active Support
Rails 4.0 刪除了 ERB::Util#json_escape
的 j
別名,因為 j
已經用於 ActionView::Helpers::JavaScriptHelper#escape_javascript
。
10.8.1 快取
快取方法在 Rails 3.x 和 4.0 之間發生了變化。您應該更改快取名稱空間 並使用冷快取推出。
10.9 Helpers 載入順序
從多個目錄載入 helpers 的順序在 Rails 4.0 中發生了變化。以前,它們被收集起來,然後按字母順序排序。升級到 Rails 4.0 後,helpers 將保留載入目錄的順序,並且只會在每個目錄中按字母順序排序。除非您明確使用 helpers_path
引數,否則此更改只會影響從引擎載入 helpers 的方式。如果您依賴排序,則應檢查升級後是否有正確的方法可用。如果你想改變引擎載入的順序,你可以使用 config.railties_order=
方法。
10.10 Active Record Observer 和 Action Controller Sweeper
ActiveRecord::Observer
和 ActionController::Caching::Sweeper
已被提取到 rails-observers
gem。如果您需要這些功能,您將需要新增 rails-observers
gem。
10.11 鏈輪-rails
-
assets:precompile:primary
和assets:precompile:all
已被刪除。請改用assets:precompile
。 -
應將
config.assets.compress
選項更改為config.assets.js_compressor
,例如:config.assets.js_compressor = :uglifier
10.12 sass-rails
- 不推薦使用帶有兩個引數的
asset-url
。例如:asset-url("rails.png", image)
變為asset-url("rails.png")
。
11 從 Rails 3.1 升級到 Rails 3.2
如果您的應用程式當前在任何早於 3.1.x 的 Rails 版本上,您 在嘗試更新到 Rails 3.2 之前,應該先升級到 Rails 3.1。
以下更改的目標在於將您的應用程序升級到最新版本 Rails 的 3.2.x 版本。
11.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
11.2 設定/環境/development.rb
您應該將幾個新的設定設定新增到您的開發環境中:
# 對 Active Record models 的批量賦值保護引發異常
config.active_record.mass_assignment_sanitizer = :strict
# 記錄查詢時間超過這個的查詢計劃(有效
# 使用 SQLite、MySQL 和 PostgreSQL)
config.active_record.auto_explain_threshold_in_seconds = 0.5
11.3 設定/環境/test.rb
mass_assignment_sanitizer
設定設定也應該新增到 config/environments/test.rb
:
# 對 Active Record models 的批量賦值保護引發異常
config.active_record.mass_assignment_sanitizer = :strict
11.4 供應商/外掛
Rails 3.2 棄用 vendor/plugins
和 Rails 4.0 將完全刪除它們。雖然作為 Rails 3.2 升級的一部分並不是絕對必要的,但您可以通過將它們提取到 gem 並將它們新增到您的 Gemfile
來開始替換任何外掛。如果您選擇不讓它們成為寶石,您可以將它們移動到 lib/my_plugin/*
中,並在 config/initializers/my_plugin.rb
中新增適當的初始化程式。
11.5 Active Record
選項 :dependent => :restrict
已從 belongs_to
中刪除。如果你想阻止刪除物件,如果有任何關聯物件,你可以設定 :dependent => :destroy
並在從任何關聯物件的銷燬 callbacks 檢查是否存在 association 後返回 false
。
12 從 Rails 3.0 升級到 Rails 3.1
如果您的應用程式當前在任何早於 3.0.x 的 Rails 版本上,您應該在嘗試更新到 Rails 3.1 之前升級到 Rails 3.0。
以下更改的目標在於將您的應用程序升級到 Rails 3.1.12,即 Rails 的最後一個 3.1.x 版本。
12.1 Gemfile
對 Gemfile
進行以下更改。
gem 'rails', '3.1.12'
gem 'mysql2'
# 新的 asset pipeline 需要
group :assets do
gem 'sass-rails', '~> 3.1.7'
gem 'coffee-rails', '~> 3.1.1'
gem 'uglifier', '>= 1.0.3'
end
# jQuery 是 Rails 3.1 中預設的 JavaScript 庫
gem 'jquery-rails'
12.2 config/application.rb
asset pipeline 需要新增以下內容:
config.assets.enabled = true
config.assets.version = '1.0'
如果您的應用程式對資源使用“/assets”路由,您可能需要更改用於資產的字首以避免衝突:
# 預設為'/assets'
config.assets.prefix = '/asset-files'
12.3 設定/環境/development.rb
刪除 RJS 設定 config.action_view.debug_rjs = true
。
如果啟用 asset pipeline,請新增這些設定:
# 不壓縮資產
config.assets.compress = false
# 展開載入資產的行
config.assets.debug = true
12.4 config/environments/production.rb
同樣,下面的大部分更改都是針對 asset pipeline 的。您可以在 Asset Pipeline 指南中閱讀有關這些的更多資訊。
# 壓縮 JavaScript 和 CSS
config.assets.compress = true
# 如果缺少預編譯資產,不要回退到資產管道
config.assets.compile = false
# 為資產 URL 產生摘要
config.assets.digest = true
# 預設為 Rails.root.join("public/assets")
# config.assets.manifest = YOUR_PATH
# 預編譯附加資產(application.js、application.css 和所有非 JS/CSS 都已新增)
# config.assets.precompile += %w( admin.js admin.css )
# 強制通過 SSL 訪問應用程式,使用 Strict-Transport-Security,並使用安全的 cookies。
# config.force_ssl = true
12.5 設定/環境/test.rb
您可以通過在測試環境中新增這些內容來幫助測試效能:
# 設定靜態資源伺服器以使用 Cache-Control 進行效能測試
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=3600'
}
12.6 config/initializers/wrap_parameters.rb
如果您希望將引數包裝到巢狀雜湊中,請使用以下內容新增此檔案。這在新應用程式中預設開啟。
# 修改這個檔案的時候一定要重啟伺服器。
# 該檔案包含 ActionController::ParamsWrapper 的設定
# 預設啟用。
# 為 JSON 啟用引數包裝。您可以通過將 :format 設定為空陣列來禁用此功能。
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
# 預設禁用 JSON 中的根元素。
ActiveSupport.on_load(:active_record) do
self.include_root_in_json = false
end
12.7 設定/初始化程式/session_store.rb
您需要將會話 key 更改為新的內容,或刪除所有 sessions:
# 在 config/initializers/session_store.rb
AppName::Application.config.session_store :cookie_store, key: 'SOMETHINGNEW'
或者
$ bin/rake db:sessions:clear
12.8 移除 views 中資產 helpers 引用中的 :cache 和 :concat 選項
- 對於 Asset Pipeline,不再使用 :cache 和 :concat 選項,請從 views 中刪除這些選項。
回饋
我們鼓勵您幫助提高本指南的品質。
如果您發現任何拼寫錯誤或資訊錯誤,請提供回饋。 要開始回饋,您可以閱讀我們的 回饋 部分。
您還可能會發現不完整的內容或不是最新的內容。 請務必為 main 新增任何遺漏的文件。假設是 非穩定版指南(edge guides) 請先驗證問題是否已經在主分支上解決。 請前往 Ruby on Rails 指南寫作準則 查看寫作風格和慣例。
如果由於某種原因您發現要修復的內容但無法自行修補,請您 提出 issue。
關於 Ruby on Rails 的任何類型的討論歡迎提供任何文件至 rubyonrails-docs 討論區。