edge
更多資訊請參考 rubyonrails.org: 更多 Ruby on Rails

Ruby on Rails 3.2 發行說明

Rails 3.2 的亮點:

這些發行說明僅涵蓋主要更改。要了解各種錯誤修復和更改,請參閱更改日誌或查看 GitHub 上主要 Rails 存儲庫中的提交列表

1 升級到 Rails 3.2

如果您正在升級現有應用程序,建議在進行升級之前進行良好的測試覆蓋。如果您尚未升級到 Rails 3.1,請先升級到該版本,並確保您的應用程序運行正常,然後再嘗試升級到 Rails 3.2。然後請注意以下更改:

1.1 Rails 3.2 需要至少 Ruby 1.8.7

Rails 3.2 需要 Ruby 1.8.7 或更高版本。官方已正式停止支援之前的所有 Ruby 版本,您應盡早升級。Rails 3.2 也與 Ruby 1.9.2 兼容。

提示:請注意,Ruby 1.8.7 p248 和 p249 存在序列化錯誤,會導致 Rails 崩潰。Ruby Enterprise Edition 自 1.8.7-2010.02 版本以來已修復了這些問題。至於 1.9 版本,Ruby 1.9.1 無法使用,因為它會直接崩潰,所以如果您想使用 1.9.x,請轉用 1.9.2 或 1.9.3 版本以確保順利運行。

1.2 應用程序中需要更新的內容

  • 更新您的 Gemfile,依賴於以下版本:

    • rails = 3.2.0
    • sass-rails ~> 3.2.3
    • coffee-rails ~> 3.2.1
    • uglifier >= 1.0.3
  • Rails 3.2 不再支援 vendor/plugins,Rails 4.0 將完全刪除這些插件。您可以將這些插件提取為 gems,並將它們添加到您的 Gemfile 中以替換它們。如果您選擇不將它們作為 gems 使用,您可以將它們移動到 lib/my_plugin/*,並在 config/initializers/my_plugin.rb 中添加適當的初始化程式。

  • config/environments/development.rb 中需要添加幾個新的配置更改:

    # 對 Active Record 模型的批量賦值保護引發異常
    config.active_record.mass_assignment_sanitizer = :strict
    
    # 對於執行時間超過此閾值的查詢記錄查詢計劃(適用於 SQLite、MySQL 和 PostgreSQL)
    config.active_record.auto_explain_threshold_in_seconds = 0.5
    

    mass_assignment_sanitizer 配置也需要在 config/environments/test.rb 中添加:

    # 對 Active Record 模型的批量賦值保護引發異常
    config.active_record.mass_assignment_sanitizer = :strict
    

1.3 引擎中需要更新的內容

script/rails 中註釋下方的代碼替換為以下內容:

ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/your_engine_name/engine', __FILE__)

require "rails/all"
require "rails/engine/commands"

2 建立一個 Rails 3.2 應用程式

# 您應該已經安裝了 'rails' RubyGem
$ rails new myapp
$ cd myapp

2.1 管理 Gems

Rails 現在使用位於應用程式根目錄下的 Gemfile 來確定您的應用程式所需的 Gems。這個 Gemfile 會被 Bundler gem 處理,然後安裝所有相依的 Gems。它甚至可以將所有相依的 Gems 安裝到您的應用程式本地,這樣就不會依賴於系統的 Gems。

更多資訊:Bundler 首頁

2.2 沿用最新版本

BundlerGemfile 讓您的 Rails 應用程式凍結變得非常容易,只需使用新的專用 bundle 命令即可。如果您想直接從 Git 倉庫捆綁,可以使用 --edge 參數:

$ rails new myapp --edge

如果您有一個本地的 Rails 倉庫並且想要使用它來生成應用程式,可以使用 --dev 參數:

$ ruby /path/to/rails/railties/bin/rails new myapp --dev

3 主要功能

3.1 更快的開發模式和路由

Rails 3.2 提供了一個明顯更快的開發模式。受到 Active Reload 的啟發,Rails 只在文件實際更改時重新載入類別。在較大的應用程式上,性能提升非常明顯。由於新的 Journey 引擎,路由識別速度也大幅提升。

3.2 自動查詢解釋

Rails 3.2 提供了一個很好的功能,通過在 ActiveRecord::Relation 中定義一個 explain 方法,解釋 Arel 生成的查詢。例如,您可以運行像 puts Person.active.limit(5).explain 這樣的命令,並解釋 Arel 生成的查詢。這可以用於檢查正確的索引和進一步的優化。

在開發模式下,運行時間超過半秒的查詢會自動進行解釋。當然,這個閾值可以更改。

3.3 標記日誌

在運行多用戶、多帳戶的應用程式時,能夠按照誰做了什麼來過濾日誌是非常有幫助的。Active Support 中的 TaggedLogging 正好可以通過在日誌行上標記子域名、請求 ID 和其他任何有助於調試此類應用程式的內容來實現。

4 文件

從 Rails 3.2 開始,Rails 指南可在 Kindle 上使用,並且可在 iPad、iPhone、Mac、Android 等設備上使用免費的 Kindle 閱讀應用程式。

5 Railties

  • 通過僅在相依文件更改時重新載入類別,加快開發速度。可以通過將 config.reload_classes_only_on_change 設置為 false 來關閉此功能。

  • 新的應用程式在環境配置文件中獲得了一個 config.active_record.auto_explain_threshold_in_seconds 標誌。在 development.rb 中設置為 0.5,在 production.rb 中註釋掉。在 test.rb 中沒有提及。

  • 新增了config.exceptions_app,用於設置當發生異常時ShowException中間件調用的異常應用程序。默認為ActionDispatch::PublicExceptions.new(Rails.public_path)

  • 新增了DebugExceptions中間件,其中包含從ShowExceptions中間件中提取的功能。

  • rake routes中顯示已掛載引擎的路由。

  • 允許使用config.railties_order更改railties的加載順序,例如:

    config.railties_order = [Blog::Engine, :main_app, :all]
    
  • 對於沒有內容的API請求,Scaffold返回204 No Content。這使得Scaffold可以直接與jQuery配合使用。

  • 更新Rails::Rack::Logger中間件,將config.log_tags中設置的任何標籤應用於ActiveSupport::TaggedLogging。這使得可以輕鬆地將日誌行標記為調試信息,例如子域和請求ID,這在調試多用戶生產應用程序時非常有用。

  • 可以在~/.railsrc中設置rails new的默認選項。您可以在家目錄中的.railsrc配置文件中指定要在每次運行rails new時使用的額外命令行參數。

  • destroy添加了別名d。這對於引擎也有效。

  • Scaffold和model生成器的屬性默認為字符串。這允許以下操作:bin/rails g scaffold Post title body:text author

  • 允許scaffold/model/migration生成器接受“index”和“uniq”修飾符。例如,

    bin/rails g scaffold Post title:string:index author:uniq price:decimal{7,2}
    

    將為titleauthor創建索引,後者將是唯一索引。某些類型(如decimal)接受自定義選項。在示例中,price將是一個decimal列,其精度和縮放分別設置為7和2。

  • 將gem從默認的Gemfile中刪除。

  • 刪除了舊的插件生成器rails generate plugin,改用rails plugin new命令。

  • 刪除了舊的config.paths.app.controller API,改用config.paths["app/controller"]

5.1 廢棄

  • Rails::Plugin已被廢棄,將在Rails 4.0中刪除。請使用gems或bundler與路徑或git依賴項代替將插件添加到vendor/plugins中。

6 Action Mailer

  • mail版本升級到2.4.0。

  • 刪除了自Rails 3.0起被廢棄的舊Action Mailer API。

7 Action Pack

7.1 Action Controller

  • ActiveSupport::Benchmarkable設置為ActionController::Base的默認模塊,因此#benchmark方法再次在控制器上下文中可用,就像以前一樣。

  • gzip選項添加到caches_page。可以使用page_cache_compression在全局配置默認選項。

  • 當您使用:only:except條件指定佈局並且這些條件失敗時,Rails現在將使用您的默認佈局(例如“layouts/application”)。 ruby class CarsController layout 'single_car', :only => :show end

當請求進入 :show 動作時,Rails 將使用 layouts/single_car 作為佈局,當請求進入其他動作時,將使用 layouts/application(或者如果存在的話,使用 layouts/cars)作為佈局。

  • 如果提供了 :as 選項,form_for 將使用 #{action}_#{as} 作為 CSS 類和 id。較早版本使用 #{as}_#{action}

  • 在 Active Record 模型上,ActionController::ParamsWrapper 現在只包裝已設置的 attr_accessible 屬性。如果沒有設置,只會包裝 attribute_names 類方法返回的屬性。這修復了通過將它們添加到 attr_accessible 來包裝嵌套屬性的問題。

  • 每次 before 回調停止時,日誌都會記錄 "Filter chain halted as CALLBACKNAME rendered or redirected"。

  • ActionDispatch::ShowExceptions 進行了重構。控制器負責選擇是否顯示異常。可以在控制器中重寫 show_detailed_exceptions? 以指定哪些請求應該提供錯誤的調試信息。

  • Responders 現在對於沒有響應主體的 API 請求返回 204 No Content(與新的腳手架一樣)。

  • ActionController::TestCase 的 cookies 進行了重構。現在,測試用例中分配 cookies 應該使用 cookies[]

cookies[:email] = '[email protected]'
get :index
assert_equal '[email protected]', cookies[:email]

要清除 cookies,使用 clear

cookies.clear
get :index
assert_nil cookies[:email]

我們現在不再寫出 HTTP_COOKIE,cookie jar 在請求之間是持久的,因此如果您需要操作測試的環境,您需要在 cookie jar 創建之前進行操作。

  • 如果未提供 :typesend_file 現在將從文件擴展名猜測 MIME 類型。

  • 添加了 PDF、ZIP 和其他格式的 MIME 類型條目。

  • 允許 fresh_when/stale? 接受記錄而不是選項哈希。

  • 將缺少 CSRF token 的警告日誌級別從 :debug 更改為 :warn

  • 資源應該默認使用請求協議,如果沒有請求可用,則默認為相對協議。

7.1.1 廢棄

  • 在父控制器設置了顯式佈局的控制器中,已廢棄隱含的佈局查找:
class ApplicationController
  layout "application"
end

class PostsController < ApplicationController
end

在上面的示例中,PostsController 將不再自動查找 posts 佈局。如果需要此功能,可以從 ApplicationController 中刪除 layout "application",或者在 PostsController 中明確將其設置為 nil

  • 已廢棄 ActionController::UnknownAction,改用 AbstractController::ActionNotFound

  • 已廢棄 ActionController::DoubleRenderError,改用 AbstractController::DoubleRenderError

  • 已廢棄 method_missing,改用 action_missing 來處理缺少的動作。

  • 已廢棄 ActionController#rescue_actionActionController#initialize_template_classActionController#assign_shortcuts

    Action Dispatch

  • 新增 config.action_dispatch.default_charset 用於配置 ActionDispatch::Response 的預設字符集。

  • 新增 ActionDispatch::RequestId 中間件,可將唯一的 X-Request-Id 標頭提供給回應,並啟用 ActionDispatch::Request#uuid 方法。這使得在堆疊中輕鬆追蹤請求的端到端,並在混合日誌(如 Syslog)中識別個別請求。

  • ShowExceptions 中間件現在接受一個異常應用程序,該應用程序負責在應用程序失敗時呈現異常。應用程序使用 env["action_dispatch.exception"] 中的異常副本和重寫狀態碼的 PATH_INFO 調用。

  • 允許通過 railtie 配置救援響應,如 config.action_dispatch.rescue_responses

7.1.2 廢棄功能

  • 廢棄在控制器層級設置預設字符集的能力,請改用新的 config.action_dispatch.default_charset

7.2 Action View

  • ActionView::Helpers::FormBuilder 中新增對 button_tag 的支援。此支援模仿 submit_tag 的默認行為。

    <%= form_for @post do |f| %>
      <%= f.button %>
    <% end %>
    
  • 日期輔助方法接受一個新選項 :use_two_digit_numbers => true,該選項在顯示月份和日期的選擇框時添加前導零,而不更改相應的值。例如,這對於顯示 ISO 8601 格式的日期(如 '2011-08-01')非常有用。

  • 您可以為表單提供一個命名空間,以確保表單元素的 id 屬性的唯一性。生成的 HTML id 將在命名空間屬性前加上底線。

    <%= form_for(@offer, :namespace => 'namespace') do |f| %>
      <%= f.label :version, '版本' %><%= f.text_field :version %>
    <% end %>
    
  • select_year 的選項數量限制為 1000。傳遞 :max_years_allowed 選項以設置自己的限制。

  • content_tag_fordiv_for 現在可以接受一個記錄集合。如果在區塊中設置了接收參數,它還會將記錄作為第一個參數傳遞。因此,不需要再這樣做:

    @items.each do |item|
      content_tag_for(:li, item) do
        Title: <%= item.title %>
      end
    end
    

    可以這樣做:

    content_tag_for(:li, @items) do |item|
      Title: <%= item.title %>
    end
    
  • 新增 font_path 助手方法,用於計算 public/fonts 中字體資源的路徑。

7.2.1 廢棄功能

  • 廢棄將格式或處理程序傳遞給 render :template 等的能力,請改為直接提供 :handlers:formats 作為選項:render :template => "foo", :formats => [:html, :js], :handlers => :erb

7.3 Sprockets

  • 添加配置選項 config.assets.logger 以控制 Sprockets 的日誌記錄。將其設置為 false 可關閉日誌記錄,設置為 nil 則默認使用 Rails.logger

    Active Record

  • 布林欄位的'on'和'ON'值會被轉換為true。

  • timestamps方法創建created_atupdated_at欄位時,默認將它們設置為非空。

  • 實現了ActiveRecord::Relation#explain

  • 實現了ActiveRecord::Base.silence_auto_explain,允許用戶在區塊內選擇性禁用自動EXPLAIN。

  • 對於慢查詢,實現了自動EXPLAIN日誌記錄。一個新的配置參數config.active_record.auto_explain_threshold_in_seconds決定了什麼被視為慢查詢。將其設置為nil將禁用此功能。默認值在開發模式下為0.5,在測試和生產模式下為nil。Rails 3.2在SQLite、MySQL(mysql2 adapter)和PostgreSQL中支持此功能。

  • 添加了ActiveRecord::Base.store,用於聲明簡單的單列鍵值存儲。

    class User < ActiveRecord::Base
      store :settings, accessors: [ :color, :homepage ]
    end
    
    u = User.new(color: 'black', homepage: '37signals.com')
    u.color                          # 存儲的屬性訪問器
    u.settings[:country] = 'Denmark' # 任何屬性,即使沒有指定訪問器
    
  • 添加了僅適用於特定範圍的遷移的選項,這允許僅運行來自一個引擎的遷移(例如,撤銷需要被刪除的引擎的更改)。

    rake db:migrate SCOPE=blog
    
  • 從引擎複製的遷移現在帶有引擎名稱的範圍,例如01_create_posts.blog.rb

  • 實現了ActiveRecord::Relation#pluck方法,該方法直接從底層表格返回一個列值的數組。這也適用於序列化的屬性。

    Client.where(:active => true).pluck(:id)
    # SELECT id from clients where active = 1
    
  • 生成的關聯方法被創建在一個單獨的模塊中,以允許重寫和組合。對於名為MyModel的類,該模塊名為MyModel::GeneratedFeatureMethods。它被立即包含到模型類中,在Active Model中定義的generated_attributes_methods模塊之後,因此關聯方法將覆蓋相同名稱的屬性方法。

  • 添加了ActiveRecord::Relation#uniq以生成唯一的查詢。

    Client.select('DISTINCT name')
    

    ..可以寫成:

    Client.select(:name).uniq
    

    這也允許您在關聯中取消唯一性:

    Client.select(:name).uniq.uniq(false)
    
  • 在SQLite、MySQL和PostgreSQL适配器中支持索引排序。

  • 允許關聯的:class_name選項接受符號,除了字符串。這是為了避免混淆新手,並與其他選項(如:foreign_key)一致,它們已經允許使用符號或字符串。

    has_many :clients, :class_name => :Client # 注意符號需要大寫
    
  • 在開發模式下,db:drop也會刪除測試數據庫,以與db:create對稱。

  • 在MySQL中,不區分大小寫的唯一性驗證在列已經使用不區分大小寫排序時,避免了調用LOWER。

  • 事務性固定裝置列舉所有活動的數據庫連接。您可以在不禁用事務性固定裝置的情況下在不同的連接上測試模型。

  • 在Active Record中添加了first_or_createfirst_or_create!first_or_initialize方法。這比舊的find_or_create_by動態方法更好,因為它更清楚地指出了用於查找記錄的參數和用於創建記錄的參數。

    User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson")
    
  • 在Active Record對象中添加了with_lock方法,該方法開始一個事務,對對象進行鎖定(悲觀鎖定)並且將控制權傳遞給塊。該方法接受一個(可選的)參數並將其傳遞給lock!

    這使得可以這樣編寫代碼:

    class Order < ActiveRecord::Base
      def cancel!
        transaction do
          lock!
          # ... 取消邏輯
        end
      end
    end
    

    等價於:

    class Order < ActiveRecord::Base
      def cancel!
        with_lock do
          # ... 取消邏輯
        end
      end
    end
    

7.4 廢棄

  • 在線程中自動關閉連接已被廢棄。例如,以下代碼已被廢棄:

    Thread.new { Post.find(1) }.join
    

    應該在線程結束時關閉數據庫連接:

    Thread.new {
      Post.find(1)
      Post.connection.close
    }.join
    

    只有在應用程序代碼中生成線程的人需要關注此更改。

  • set_table_nameset_inheritance_columnset_sequence_nameset_primary_keyset_locking_column方法已被廢棄。請改用賦值方法。例如,使用self.table_name=代替set_table_name

    class Project < ActiveRecord::Base
      self.table_name = "project"
    end
    

    或者定義自己的self.table_name方法:

    class Post < ActiveRecord::Base
      def self.table_name
        "special_" + super
      end
    end
    
    Post.table_name # => "special_posts"
    

8 Active Model

  • 添加了ActiveModel::Errors#added?方法,用於檢查是否已添加特定的錯誤。

  • 添加了使用strict => true定義嚴格驗證的能力,當驗證失敗時始終引發異常。

  • 提供了mass_assignment_sanitizer作為一個簡單的API來替換清潔器行為。同時支持logger(默認)和strict清潔器行為。

8.1 廢棄

  • ActiveModel::AttributeMethods中廢棄了define_attr_method,因為它只存在於支持Active Record中的set_table_name等方法,而這些方法本身已被廢棄。

  • ActiveModel::Naming中廢棄了Model.model_name.partial_path,改用model.to_partial_path

9 Active Resource

  • 重定向響應:303 See Other和307 Temporary Redirect現在的行為與301 Moved Permanently和302 Found相同。

10 Active Support

  • 添加了ActiveSupport:TaggedLogging,可以將任何標準的Logger類包裝起來,提供標記功能。

    Logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
    
    Logger.tagged("BCX") { Logger.info "Stuff" }
    # 輸出日誌 "[BCX] Stuff"
    
    Logger.tagged("BCX", "Jason") { Logger.info "Stuff" }
    # 輸出日誌 "[BCX] [Jason] Stuff"
    
    Logger.tagged("BCX") { Logger.tagged("Jason") { Logger.info "Stuff" } }
    # 輸出日誌 "[BCX] [Jason] Stuff"
    
  • DateTimeDateTime中的beginning_of_week方法接受一个可选参数,表示假设一周从哪一天开始。

  • ActiveSupport::Notifications.subscribed提供了在块运行时订阅事件的功能。

  • 定义了新的方法Module#qualified_const_defined?Module#qualified_const_getModule#qualified_const_set,它们类似于标准API中的相应方法,但接受限定的常量名称。

  • 添加了#deconstantize,它与inflections中的#demodulize相对应。它从限定的常量名称中移除最右边的部分。

  • 添加了safe_constantize,它将一个字符串转换为常量,但如果常量(或其中的一部分)不存在,则返回nil而不是引发异常。

  • 当使用Array#extract_options!时,现在将ActiveSupport::OrderedHash标记为可提取。

  • 添加了Array#prepend作为Array#unshift的别名,以及Array#append作为Array#<<的别名。

  • 对于Ruby 1.9,空字符串的定义已扩展到Unicode空白字符。此外,在Ruby 1.8中,表意空格U+3000被视为空白字符。

  • inflector理解首字母缩略词。

  • 添加了Time#all_dayTime#all_weekTime#all_quarterTime#all_year作为生成范围的一种方式。

    Event.where(:created_at => Time.now.all_week)
    Event.where(:created_at => Time.now.all_day)
    
  • 添加了instance_accessor: false作为Class#cattr_accessor和相关方法的选项。

  • 当给定一个接受参数的块时,ActiveSupport::OrderedHash#each#each_pair现在具有不同的行为。

  • 添加了ActiveSupport::Cache::NullStore,用于开发和测试。

  • 删除了ActiveSupport::SecureRandom,改用标准库中的SecureRandom

10.1 弃用

  • 弃用了ActiveSupport::Base64,改用::Base64

  • 弃用了ActiveSupport::Memoizable,改用Ruby的记忆化模式。

  • 弃用了Module#synchronize,没有替代方法。请使用Ruby标准库中的monitor。

  • 弃用了ActiveSupport::MessageEncryptor#encryptActiveSupport::MessageEncryptor#decrypt

  • 弃用了ActiveSupport::BufferedLogger#silence。如果要在某个块中禁止日志记录,请更改该块的日志级别。

  • 弃用了ActiveSupport::BufferedLogger#open_log。这个方法本来就不应该是公开的。

  • 弃用了ActiveSupport::BufferedLogger自动创建日志文件目录的行为。请确保在实例化之前创建日志文件的目录。

  • 弃用了ActiveSupport::BufferedLogger#auto_flushing。请设置底层文件句柄的同步级别,或调整文件系统。现在刷新由文件系统缓存控制。

    f = File.open('foo.log', 'w')
    f.sync = true
    ActiveSupport::BufferedLogger.new f
    
  • 弃用了ActiveSupport::BufferedLogger#flush。请在文件句柄上设置同步,或调整文件系统。

11 致谢

请参阅Rails的完整贡献者列表,感谢那些花费了许多时间使Rails成为稳定和强大的框架的人。向他们致敬。 Rails 3.2 發行說明是由 Vijay Dev 編譯的。

回饋

歡迎協助提升本指南的品質。

如果您發現任何錯別字或事實錯誤,請貢獻您的力量。 開始之前,您可以閱讀我們的 文件貢獻 部分。

您也可能會發現不完整的內容或過時的資訊。 請為主要的文件補充任何遺漏的內容。請先檢查 Edge 指南,以確認問題是否已經修復或尚未在主分支上修復。 請參考 Ruby on Rails 指南指引 以了解風格和慣例。

如果您發現需要修復但無法自行修補的問題,請 開啟一個問題

最後但同樣重要的是,關於 Ruby on Rails 文件的任何討論都非常歡迎在 官方 Ruby on Rails 論壇 上進行。