更多資訊請見 rubyonrails.org:

1 升級至 Rails 4.2

如果您要升級現有的應用程式,最好先有良好的測試涵蓋率。您也應該先升級到 Rails 4.1(如果您尚未升級),並在嘗試升級到 Rails 4.2 之前,確保您的應用程式仍然如預期般運作。升級時需要注意的事項清單可在升級 Ruby on Rails指南中找到。

2 主要功能

2.1 Active Job

Active Job 是 Rails 4.2 中的新框架。它是佇列系統(例如 ResqueDelayed JobSidekiq 等)之上的通用介面。

使用 Active Job API 撰寫的作業會透過它們各自的配接器在任何支援的佇列上執行。Active Job 預先設定了內嵌執行器,可立即執行作業。

作業通常需要將 Active Record 物件作為引數。Active Job 會將物件參考作為 URI(統一資源識別碼)傳遞,而不是編組物件本身。新的 Global ID 程式庫會建立 URI 並查閱它們參考的物件。透過在內部使用 Global ID,將 Active Record 物件作為作業引數傳遞即可正常運作。

例如,如果 trashable 是 Active Record 物件,則此作業可以順利執行,且不涉及任何序列化

class TrashableCleanupJob < ActiveJob::Base
  def perform(trashable, depth)
    trashable.cleanup(depth)
  end
end

請參閱Active Job 基礎指南以取得更多資訊。

2.2 非同步郵件

Action Mailer 現在建立在 Active Job 之上,並隨附 deliver_later 方法,該方法會透過佇列傳送電子郵件,因此如果佇列是非同步的(預設的內嵌佇列會封鎖),則不會封鎖控制器或模型。

使用 deliver_now 仍然可以立即傳送電子郵件。

2.3 Adequate Record

Adequate Record 是 Active Record 中的一組效能改進,可讓常見的 findfind_by 呼叫以及某些關聯查詢速度提高多達 2 倍。

它的運作方式是將常見的 SQL 查詢快取為預備陳述式,並在類似的呼叫中重複使用它們,從而跳過後續呼叫中的大多數查詢產生工作。如需更多詳細資訊,請參閱 Aaron Patterson 的部落格文章

Active Record 將在支援的操作上自動利用此功能,而無需使用者介入或程式碼變更。以下是一些支援的操作範例

Post.find(1)  # First call generates and cache the prepared statement
Post.find(2)  # Subsequent calls reuse the cached prepared statement

Post.find_by_title('first post')
Post.find_by_title('second post')

Post.find_by(title: 'first post')
Post.find_by(title: 'second post')

post.comments
post.comments(true)

務必強調,如以上範例所示,預備陳述式不會快取方法呼叫中傳遞的值;相反地,它們具有這些值的預留位置。

快取不會用於以下情況

  • 模型具有預設範圍
  • 模型使用單一資料表繼承
  • find 具有 ID 清單,例如

    # not cached
    Post.find(1, 2, 3)
    Post.find([1,2])
    
  • find_by 具有 SQL 片段

    Post.find_by('published_at < ?', 2.weeks.ago)
    

2.4 Web Console

使用 Rails 4.2 產生新的應用程式現在預設隨附 Web Console gem。Web Console 會在每個錯誤頁面上新增互動式 Ruby 主控台,並提供 console 視圖和控制器輔助方法。

錯誤頁面上的互動式主控台可讓您在例外狀況發生的位置內容中執行程式碼。如果在視圖或控制器中的任何位置呼叫 console 輔助方法,則會在轉譯完成後啟動具有最終內容的互動式主控台。

2.5 外鍵支援

遷移 DSL 現在支援新增和移除外鍵。它們也會被傾印到 schema.rb 中。目前,只有 mysqlmysql2postgresql 配接器支援外鍵。

# add a foreign key to `articles.author_id` referencing `authors.id`
add_foreign_key :articles, :authors

# add a foreign key to `articles.author_id` referencing `users.lng_id`
add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"

# remove the foreign key on `accounts.branch_id`
remove_foreign_key :accounts, :branches

# remove the foreign key on `accounts.owner_id`
remove_foreign_key :accounts, column: :owner_id

請參閱 add_foreign_keyremove_foreign_key 的 API 文件,以取得完整說明。

3 不相容性

先前已棄用的功能已移除。請參閱個別元件以取得此版本中新的棄用。

以下變更可能需要在升級後立即採取行動。

3.1 具有字串引數的 render

先前,在控制器動作中呼叫 render "foo/bar" 等於 render file: "foo/bar"。在 Rails 4.2 中,這已變更為表示 render template: "foo/bar"。如果您需要轉譯檔案,請將您的程式碼變更為使用明確形式(render file: "foo/bar")。

3.2 respond_with / 類別層級 respond_to

respond_with 和對應的類別層級 respond_to 已移至 responders gem。將 gem "responders", "~> 2.0" 新增至您的 Gemfile 以使用它

# app/controllers/users_controller.rb

class UsersController < ApplicationController
  respond_to :html, :json

  def show
    @user = User.find(params[:id])
    respond_with @user
  end
end

執行個體層級 respond_to 不受影響

# app/controllers/users_controller.rb

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    respond_to do |format|
      format.html
      format.json { render json: @user }
    end
  end
end

3.3 rails server 的預設主機

由於 Rack 中的變更rails server 現在預設在 localhost 上接聽,而不是 0.0.0.0。這應該對標準開發工作流程產生最小的影響,因為 http://127.0.0.1:3000https://127.0.0.1:3000 仍會像之前一樣在您的電腦上運作。

但是,透過此變更,您將無法再從不同的電腦存取 Rails 伺服器,例如,如果您的開發環境在虛擬機器中,並且您想要從主機存取它。在這種情況下,請使用 rails server -b 0.0.0.0 啟動伺服器以恢復舊的行為。

如果您這樣做,請務必正確設定防火牆,讓只有您網路上受信任的電腦可以存取您的開發伺服器。

3.4 render 的狀態選項符號已變更

由於 Rack 的變更render 方法接受的 :status 選項符號已變更。

  • 306::reserved 已被移除。
  • 413::request_entity_too_large 已被重新命名為 :payload_too_large
  • 414::request_uri_too_long 已被重新命名為 :uri_too_long
  • 416::requested_range_not_satisfiable 已被重新命名為 :range_not_satisfiable

請注意,如果使用未知的符號呼叫 render,回應狀態將預設為 500。

3.5 HTML 清理器

HTML 清理器已被替換為基於 LoofahNokogiri 構建的全新、更穩健的實作。新的清理器更安全,其清理功能更強大且更具彈性。

由於新的演算法,對於某些病態輸入,清理後的輸出可能會有不同。

如果您對舊清理器的確切輸出有特殊需求,您可以將 rails-deprecated_sanitizer gem 新增到 Gemfile 中,以保留舊的行為。由於是選擇性加入,此 gem 不會發出棄用警告。

rails-deprecated_sanitizer 僅支援 Rails 4.2;不會為 Rails 5.0 維護。

請參閱這篇部落格文章,以取得有關新清理器變更的更多詳細資訊。

3.6 assert_select

assert_select 現在基於 Nokogiri。因此,某些先前有效的選擇器現在不受支援。如果您的應用程式正在使用任何這些拼寫,您將需要更新它們。

  • 如果屬性選擇器中的值包含非字母數字字元,則可能需要加上引號。

    # before
    a[href=/]
    a[href$=/]
    
    # now
    a[href="/"]
    a[href$="/"]
    
  • 從包含格式不正確的 HTML 和不正確巢狀元素的 HTML 原始碼建構的 DOM 可能會有所不同。

    例如

    # content: <div><i><p></i></div>
    
    # before:
    assert_select('div > i')  # => true
    assert_select('div > p')  # => false
    assert_select('i > p')    # => true
    
    # now:
    assert_select('div > i')  # => true
    assert_select('div > p')  # => true
    assert_select('i > p')    # => false
    
  • 如果選取的資料包含實體,則用於比較的選取值過去是原始的(例如 AT&amp;T),現在是已評估的(例如 AT&T)。

    # content: <p>AT&amp;T</p>
    
    # before:
    assert_select('p', 'AT&amp;T')  # => true
    assert_select('p', 'AT&T')      # => false
    
    # now:
    assert_select('p', 'AT&T')      # => true
    assert_select('p', 'AT&amp;T')  # => false
    

此外,替代的語法已變更。

現在您必須使用類似 CSS 的 :match 選擇器

assert_select ":match('id', ?)", 'comment_1'

此外,當斷言失敗時,Regexp 替代看起來會有所不同。請注意這裡的 /hello/

assert_select(":match('id', ?)", /hello/)

變為 "(?-mix:hello)"

Expected at least 1 element matching "div:match('id', "(?-mix:hello)")", found 0..
Expected 0 to be >= 1.

請參閱 Rails Dom Testing 文件以取得有關 assert_select 的更多資訊。

4 Railties

請參閱變更日誌以取得詳細的變更資訊。

4.1 移除

  • 應用程式產生器已移除 --skip-action-view 選項。( Pull Request)

  • rails application 命令已被移除,且沒有替代命令。( Pull Request)

4.2 棄用

  • 棄用了生產環境缺少 config.log_level 的情況。( Pull Request)

  • 棄用了 rake test:all,改用 rake test,因為它現在會執行 test 資料夾中的所有測試。( Pull Request)

  • 棄用了 rake test:all:db,改用 rake test:db。( Pull Request)

  • 棄用了 Rails::Rack::LogTailer,沒有替代選項。( Commit)

4.3 重要變更

  • 在預設應用程式 Gemfile 中引入了 web-console。( Pull Request)

  • 為關聯的模型產生器新增了 required 選項。( Pull Request)

  • 引入了 x 命名空間,用於定義自訂組態選項

    # config/environments/production.rb
    config.x.payment_processing.schedule = :daily
    config.x.payment_processing.retries  = 3
    config.x.super_debugger              = true
    

    這些選項隨後可透過組態物件使用

    Rails.configuration.x.payment_processing.schedule # => :daily
    Rails.configuration.x.payment_processing.retries  # => 3
    Rails.configuration.x.super_debugger              # => true
    

    (Commit)

  • 引入了 Rails::Application.config_for 以載入目前環境的組態。

    # config/exception_notification.yml
    production:
      url: http://127.0.0.1:8080
      namespace: my_app_production
    development:
      url: https://127.0.0.1:3001
      namespace: my_app_development
    
    # config/environments/production.rb
    Rails.application.configure do
      config.middleware.use ExceptionNotifier, config_for(:exception_notification)
    end
    

    (Pull Request)

  • 在應用程式產生器中引入了 --skip-turbolinks 選項,以避免產生 turbolinks 整合。( Commit)

  • 引入了 bin/setup 指令碼,作為引導應用程式時自動設定程式碼的慣例。( Pull Request)

  • 在開發環境中,config.assets.digest 的預設值已變更為 true。( Pull Request)

  • 引入了 API 以註冊 rake notes 的新擴充功能。( Pull Request)

  • 引入了 after_bundle 回呼,以用於 Rails 範本。( Pull Request)

  • 引入了 Rails.gem_version 作為方便的方法來傳回 Gem::Version.new(Rails.version)。( Pull Request)

5 Action Pack

請參閱變更日誌以取得詳細的變更資訊。

5.1 移除

  • respond_with 和類別層級的 respond_to 已從 Rails 移除,並移至 responders gem(2.0 版)。將 gem "responders", "~> 2.0" 新增至您的 Gemfile,以繼續使用這些功能。( Pull Request, 更多詳細資訊)

  • 移除了已棄用的 AbstractController::Helpers::ClassMethods::MissingHelperError,改用 AbstractController::Helpers::MissingHelperError。( Commit)

5.2 棄用

  • 棄用了 *_path 輔助程式上的 only_path 選項。( Commit)

  • 棄用了 assert_tagassert_no_tagfind_tagfind_all_tag,改用 assert_select。( Commit)

  • 棄用了將路由器的 :to 選項設定為不包含 "#" 字元的符號或字串的支援

    get '/posts', to: MyRackApp    => (No change necessary)
    get '/posts', to: 'post#index' => (No change necessary)
    get '/posts', to: 'posts'      => get '/posts', controller: :posts
    get '/posts', to: :index       => get '/posts', action: :index
    

    (Commit)

  • 棄用了 URL 輔助程式中字串索引鍵的支援

    # bad
    root_path('controller' => 'posts', 'action' => 'index')
    
    # good
    root_path(controller: 'posts', action: 'index')
    

    (Pull Request)

5.3 重要變更

  • *_filter 方法系列已從文件中移除。不建議使用它們,而應使用 *_action 方法系列

    after_filter          => after_action
    append_after_filter   => append_after_action
    append_around_filter  => append_around_action
    append_before_filter  => append_before_action
    around_filter         => around_action
    before_filter         => before_action
    prepend_after_filter  => prepend_after_action
    prepend_around_filter => prepend_around_action
    prepend_before_filter => prepend_before_action
    skip_after_filter     => skip_after_action
    skip_around_filter    => skip_around_action
    skip_before_filter    => skip_before_action
    skip_filter           => skip_action_callback
    

    如果您的應用程式目前依賴這些方法,您應該改用替代的 *_action 方法。這些方法將在未來被棄用,並最終從 Rails 中移除。

    (Commit 1, 2)

  • render nothing: true 或呈現 nil 主體不再向回應主體新增單一空格填補。( Pull Request)

  • Rails 現在會自動在 ETags 中包含範本的摘要。( Pull Request)

  • 傳遞至 URL 輔助程式的區段現在會自動逸出。( Commit)

  • 引入了 always_permitted_parameters 選項,以組態全域允許的參數。此組態的預設值為 ['controller', 'action']。( Pull Request)

  • 新增了來自 RFC 4791 的 HTTP 方法 MKCALENDAR。( Pull Request)

  • *_fragment.action_controller 通知現在會在酬載中包含控制器和動作名稱。( Pull Request)

  • 使用路由搜尋的模糊比對改善了路由錯誤頁面。( Pull Request)

  • 新增了停用記錄 CSRF 失敗的選項。( Pull Request)

  • 當 Rails 伺服器設定為提供靜態資產時,如果用戶端支援並且磁碟上有預先產生的 gzip 檔案 (.gz),則現在會提供 gzip 資產。依預設,資產管線會為所有可壓縮的資產產生 .gz 檔案。提供 gzip 檔案可最大限度地減少資料傳輸並加速資產要求。如果您在生產環境中從 Rails 伺服器提供資產,請務必使用 CDN。( Pull Request)

  • 在整合測試中呼叫 process 輔助程式時,路徑需要有前導斜線。之前您可以省略它,但那是實作的副產品,而不是有意的功能,例如

    test "list all posts" do
      get "/posts"
      assert_response :success
    end
    

6 Action View

請參閱變更日誌以取得詳細的變更資訊。

6.1 棄用

  • 棄用了 AbstractController::Base.parent_prefixes。當您想要變更尋找視圖的位置時,請覆寫 AbstractController::Base.local_prefixes。( Pull Request)

  • 棄用了 ActionView::Digestor#digest(name, format, finder, options = {})。應以雜湊形式傳遞引數。( Pull Request)

6.2 重要變更

  • render "foo/bar" 現在會展開為 render template: "foo/bar",而不是 render file: "foo/bar"。( Pull Request)

  • 表單輔助程式不再圍繞隱藏欄位產生具有內嵌 CSS 的 <div> 元素。( Pull Request)

  • 引入了 #{partial_name}_iteration 特殊本機變數,以用於以集合呈現的部分。它透過 indexsizefirst?last? 方法提供對迭代目前狀態的存取。( Pull Request)

  • 佔位符 I18n 遵循與 label I18n 相同的慣例。( Pull Request)

7 Action Mailer

請參閱變更日誌以取得詳細的變更資訊。

7.1 棄用

  • 棄用了郵件程式中的 *_path 輔助程式。請務必改用 *_url 輔助程式。( Pull Request)

  • 棄用了 deliver / deliver!,改用 deliver_now / deliver_now!。( Pull Request)

7.2 重要變更

  • link_tourl_for 預設會在範本中產生絕對 URL,不再需要傳遞 only_path: false。( Commit)

  • 引入了 deliver_later,它會在應用程式的佇列上排隊一個工作,以非同步方式傳送電子郵件。( Pull Request)

  • 新增了 show_previews 組態選項,以在開發環境之外啟用郵件程式預覽。( Pull Request)

8 Active Record

請參閱變更日誌以取得詳細的變更資訊。

8.1 移除

  • 移除了 cache_attributes 和相關方法。所有屬性都會快取。( Pull Request)

  • 移除了已棄用的方法 ActiveRecord::Base.quoted_locking_column。( Pull Request)

  • 移除了已棄用的 ActiveRecord::Migrator.proper_table_name。請改用 ActiveRecord::Migration 上的 proper_table_name 實例方法。( Pull Request)

  • 移除了未使用的 :timestamp 類型。在所有情況下都將其透明地別名為 :datetime。修復了在 Active Record 之外傳送欄類型時的不一致性,例如 XML 序列化。( Pull Request)

8.2 棄用

  • 棄用了在 after_commitafter_rollback 內部吞噬錯誤的行為。( Pull Request)

  • 棄用了對 has_many :through 關聯上自動偵測計數器快取的損壞支援。您應該改為在通過記錄的 has_manybelongs_to 關聯上手動指定計數器快取。( Pull Request)

  • 棄用了將 Active Record 物件傳遞給 .find.exists? 的行為。請先在物件上呼叫 id。(Commit 1, 2)

  • 已棄用對 PostgreSQL 範圍值(排除起始值)的不完整支援。我們目前將 PostgreSQL 範圍對應到 Ruby 範圍。此轉換並非完全可行,因為 Ruby 範圍不支援排除起始值。

    目前遞增起始值的解決方案不正確,現在已被棄用。對於我們不知道如何遞增的子類型(例如,未定義 succ),它會針對具有排除起始值的範圍引發 ArgumentError。(提交

  • 已棄用在沒有連線的情況下呼叫 DatabaseTasks.load_schema。請改用 DatabaseTasks.load_schema_current。(提交

  • 已棄用 sanitize_sql_hash_for_conditions,且沒有替代方案。使用 Relation 來執行查詢和更新是較佳的 API。(提交

  • 已棄用在不傳遞 :null 選項的情況下使用 add_timestampst.timestampsnull: true 的預設值將在 Rails 5 中變更為 null: false。(提取請求

  • 已棄用 Reflection#source_macro,且沒有替代方案,因為 Active Record 中不再需要它。(提取請求

  • 已棄用 serialized_attributes,且沒有替代方案。(提取請求

  • 已棄用在沒有欄位存在時,從 column_for_attribute 回傳 nil。它會在 Rails 5.0 中回傳一個 null 物件。(提取請求

  • 已棄用在不使用替代方案的情況下,將 .joins.preload.eager_load 用於依賴實例狀態的關聯(即那些使用帶有參數的範圍定義的關聯)。(提交

8.3 重要變更

  • SchemaDumpercreate_table 上使用 force: :cascade。這使得在外鍵存在的情況下重新載入綱要成為可能。

  • 為單數關聯新增了 :required 選項,它定義了關聯的存在驗證。(提取請求

  • ActiveRecord::Dirty 現在會偵測對可變值的就地變更。Active Record 模型上的序列化屬性在未變更時不再儲存。這也適用於其他類型,例如 PostgreSQL 上的字串欄位和 json 欄位。(提取請求 123

  • 引入了 db:purge Rake 任務,用於清空目前環境的資料庫。(提交

  • 引入了 ActiveRecord::Base#validate!,如果記錄無效,則會引發 ActiveRecord::RecordInvalid。(提取請求

  • 引入 validate 作為 valid? 的別名。(提取請求

  • touch 現在接受一次觸碰多個屬性。(提取請求

  • PostgreSQL 配接器現在支援 PostgreSQL 9.4+ 中的 jsonb 資料類型。(提取請求

  • PostgreSQL 和 SQLite 配接器不再在字串欄位上新增預設的 255 個字元限制。(提取請求

  • 在 PostgreSQL 配接器中新增了對 citext 欄位類型的支援。(提取請求

  • 在 PostgreSQL 配接器中新增了對使用者建立的範圍類型的支援。(提交

  • sqlite3:///some/path 現在解析為絕對系統路徑 /some/path。對於相對路徑,請改用 sqlite3:some/path。(先前,sqlite3:///some/path 解析為相對路徑 some/path。此行為已在 Rails 4.1 中棄用)。(提取請求

  • 新增了對 MySQL 5.6 及更高版本的秒數小數部分支援。(提取請求 12

  • 新增了 ActiveRecord::Base#pretty_print 以美觀地列印模型。(提取請求

  • ActiveRecord::Base#reload 現在的行為與 m = Model.find(m.id) 相同,表示它不再保留來自自訂 SELECT 的額外屬性。(提取請求

  • ActiveRecord::Base#reflections 現在回傳具有字串鍵而不是符號鍵的雜湊。(提取請求

  • 遷移中的 references 方法現在支援 type 選項,用於指定外鍵的類型(例如,:uuid)。(提取請求

9 Active Model

請參閱 變更日誌 以取得詳細變更。

9.1 移除

  • 已移除已棄用的 Validator#setup,且沒有替代方案。(提取請求

9.2 棄用

  • 已棄用 reset_#{attribute},改用 restore_#{attribute}。(提取請求

  • 已棄用 ActiveModel::Dirty#reset_changes,改用 clear_changes_information。(提取請求

9.3 重要變更

  • 引入 validate 作為 valid? 的別名。(提取請求

  • ActiveModel::Dirty 中引入了 restore_attributes 方法,以將變更(髒)的屬性還原為它們先前的值。(提取請求 12

  • has_secure_password 預設不再禁止空白密碼(即僅包含空格的密碼)。(提取請求

  • 如果啟用了驗證,has_secure_password 現在會驗證給定的密碼是否少於 72 個字元。(提取請求

10 Active Support

請參閱 變更日誌 以取得詳細變更。

10.1 移除

  • 已移除已棄用的 Numeric#agoNumeric#untilNumeric#sinceNumeric#from_now。(提交

  • 已移除 ActiveSupport::Callbacks 已棄用的字串型終止符。(提取請求

10.2 棄用

  • 已棄用 Kernel#silence_stderrKernel#captureKernel#quietly,且沒有替代方案。(提取請求

  • 已棄用 Class#superclass_delegating_accessor,請改用 Class#class_attribute。(提取請求

  • 已棄用 ActiveSupport::SafeBuffer#prepend!,因為 ActiveSupport::SafeBuffer#prepend 現在執行相同的功能。(提取請求

10.3 重要變更

  • 引入了一個新的組態選項 active_support.test_order,用於指定執行測試案例的順序。此選項目前預設為 :sorted,但在 Rails 5.0 中將變更為 :random。(提交

  • 現在可以在區塊中使用 Object#tryObject#try!,而無需明確的接收器。(提交提取請求

  • travel_to 測試輔助工具現在會將 usec 元件截斷為 0。(提交

  • 引入了 Object#itself 作為恆等函數。(提交 12

  • 現在可以在區塊中使用 Object#with_options,而無需明確的接收器。(提取請求

  • 引入了 String#truncate_words,用於按字數截斷字串。(提取請求

  • 新增了 Hash#transform_valuesHash#transform_values!,以簡化雜湊的值必須變更,但鍵保持不變的常見模式。(提取請求

  • humanize 變形輔助工具現在會去除任何開頭的底線。(提交

  • 引入了 Concern#class_methods 作為 module ClassMethods 的替代方案,以及 Kernel#concern 以避免 module Foo; extend ActiveSupport::Concern; end 樣板。(提交

  • 關於常數自動載入和重新載入的新指南

11 貢獻者

請參閱Rails 的完整貢獻者清單,了解為使 Rails 成為如今穩定而強大的框架而花費許多時間的許多人。向他們所有人致敬。



回到頂端