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

Ruby on Rails 2.2 發行說明

Rails 2.2 提供了幾個新功能和改進功能。這個清單涵蓋了主要的升級,但不包括每一個小的錯誤修復和更改。如果你想看到所有的內容,請查看 GitHub 上主要的 Rails 存儲庫中的 提交清單

除了 Rails,2.2 還標誌著 Ruby on Rails Guides 的推出,這是持續進行中的 Rails Guides hackfest 的第一個成果。這個網站將提供高質量的 Rails 主要功能文檔。

1 基礎設施

Rails 2.2 對保持 Rails 順暢運行並與世界其他部分連接的基礎設施來說是一個重要的版本。

1.1 國際化

Rails 2.2 提供了一個簡單的國際化系統(或者對於那些厭倦了打字的人來說,叫做 i18n)。

1.2 與 Ruby 1.9 和 JRuby 的兼容性

除了線程安全性外,還做了很多工作,使得 Rails 能夠與 JRuby 和即將推出的 Ruby 1.9 配合良好。由於 Ruby 1.9 是一個不斷變動的目標,運行最新版的 Rails 在最新版的 Ruby 上仍然是一個不確定的問題,但是 Rails 已經準備好在 Ruby 1.9 發布時過渡到該版本。

2 文檔

Rails 的內部文檔,以代碼註釋的形式,在許多地方進行了改進。此外,Ruby on Rails Guides 項目是關於主要 Rails 組件的信息的權威來源。在它的第一個正式版本中,Guides 頁面包括:

總的來說,這些指南為初學者和中級 Rails 開發人員提供了數以萬計的指導性文字。

如果你想在你的應用程序內部生成這些指南:

$ rake doc:guides

這將把指南放在 Rails.root/doc/guides 中,你可以通過在你喜歡的瀏覽器中打開 Rails.root/doc/guides/index.html 來開始瀏覽。

支援在HTTP標頭中使用ETag和最後修改時間戳記意味著Rails現在可以在收到對尚未最近修改的資源的請求時返回一個空的回應。這使您可以檢查是否需要發送回應。

class ArticlesController < ApplicationController
  def show_with_respond_to_block
    @article = Article.find(params[:id])

    # 如果請求的標頭與stale?方法提供的選項不同,則請求確實是過期的,並且觸發respond_to區塊(並且將stale?方法的選項設置在回應上)。
    #
    # 如果請求標頭匹配,則請求是新鮮的,並且不會觸發respond_to區塊。相反,將發生默認的渲染,它將檢查last-modified和etag標頭,並得出只需發送“304 Not Modified”而不是渲染模板。
    if stale?(:last_modified => @article.published_at.utc, :etag => @article)
      respond_to do |wants|
        # 正常的回應處理
      end
    end
  end

  def show_with_implied_render
    @article = Article.find(params[:id])

    # 設置回應標頭並將其與請求進行比對,如果請求是過期的(即etag或last-modified都不匹配),則默認的渲染模板將發生。
    # 如果請求是新鮮的,則默認的渲染將返回“304 Not Modified”而不是渲染模板。
    fresh_when(:last_modified => @article.published_at.utc, :etag => @article)
  end
end

3 執行緒安全性

使Rails具有執行緒安全性的工作正在Rails 2.2中推出。根據您的Web服務器基礎架構,這意味著您可以使用更少的Rails副本處理更多的請求,從而提高服務器性能並更好地利用多核心。

要在應用程式的生產模式中啟用多執行緒調度,請在config/environments/production.rb中添加以下行:

config.threadsafe!

4 Active Record

這裡有兩個重要的新增功能:事務性遷移和資料庫連接池事務。還有一個新的(更簡潔)的連接表條件語法,以及一些較小的改進。

4.1 事務性遷移

在過去,多步驟的Rails遷移一直是一個麻煩的來源。如果在遷移過程中出現問題,錯誤之前的所有更改都會變更資料庫,而錯誤之後的所有更改都不會應用。此外,遷移版本被存儲為已執行,這意味著在修復問題後無法簡單地通過rake db:migrate:redo重新執行。事務性遷移通過將遷移步驟包裝在DDL事務中來改變這一點,因此如果其中任何一個失敗,整個遷移都將被撤銷。在Rails 2.2中,事務性遷移在PostgreSQL上得到了支援。代碼可擴展到未來支援其他數據庫類型,IBM已經擴展它以支援DB2適配器。 * 主要貢獻者:Adam Wiggins * 更多資訊: * DDL 交易 * DB2 on Rails 的重要里程碑

4.2 連線池

連線池讓 Rails 可以將資料庫請求分散到一個連線池中,這個連線池的大小會增長到最大值(預設為 5,但你可以在 database.yml 中加入 pool 鍵來調整)。這有助於消除支援許多並行使用者的應用程式中的瓶頸。還有一個 wait_timeout,預設為 5 秒,表示在放棄之前等待的時間。如果需要,ActiveRecord::Base.connection_pool 可以直接存取連線池。

development:
  adapter: mysql
  username: root
  database: sample_development
  pool: 10
  wait_timeout: 10

4.3 使用 Hashes 進行連結表條件

現在可以使用 Hashes 在連結表上指定條件。如果需要在複雜的連結上進行查詢,這將非常有幫助。

class Photo < ActiveRecord::Base
  belongs_to :product
end

class Product < ActiveRecord::Base
  has_many :photos
end

# 取得所有具有無版權照片的產品:
Product.all(:joins => :photos, :conditions => { :photos => { :copyright => false }})

4.4 新的動態查詢方法

Active Record 的動態查詢家族新增了兩組新的方法。

4.4.1 find_last_by_attribute

find_last_by_attribute 方法等同於 Model.last(:conditions => {:attribute => value})

# 取得最後一位從倫敦註冊的使用者
User.find_last_by_city('London')

4.4.2 find_by_attribute!

find_by_attribute! 的新版本(加上驚嘆號)等同於 Model.first(:conditions => {:attribute => value}) || raise ActiveRecord::RecordNotFound。這個方法在找不到符合條件的記錄時,不會返回 nil,而是會拋出異常。

# 如果 'Moby' 還沒有註冊,則拋出 ActiveRecord::RecordNotFound 異常!
User.find_by_name!('Moby')

4.5 關聯尊重私有/受保護範圍

Active Record 關聯代理現在尊重代理對象上的方法範圍。之前(假設 User 有一個 has_one :account 關聯),@user.account.private_method 會調用關聯的 Account 物件上的私有方法。在 Rails 2.2 中,這將失敗;如果需要此功能,應該使用 @user.account.send(:private_method)(或將方法從私有或受保護改為公開)。請注意,如果覆寫了 method_missing,應該同時覆寫 respond_to 以匹配行為,以使關聯正常運作。

  • 主要貢獻者:Adam Milligan
  • 更多資訊:

  • rake db:migrate:redo 現在接受一個可選的VERSION來重新執行特定的遷移

  • 設置 config.active_record.timestamped_migrations = false 以使用數字前綴而不是UTC時間戳記來進行遷移。

  • 不再需要將計數緩存列(對於使用 :counter_cache => true 声明的關聯)初始化為零。

  • ActiveRecord::Base.human_name 用於對模型名稱進行國際化友好的翻譯

5 Action Controller

在控制器方面,有幾個更改將有助於整理您的路由。路由引擎中還有一些內部更改,以降低複雜應用程序的內存使用。

5.1 淺層路由嵌套

淺層路由嵌套提供了一種解決使用深度嵌套資源的已知困難的方法。使用淺層嵌套,您只需要提供足夠的信息來唯一識別要使用的資源。

map.resources :publishers, :shallow => true do |publisher|
  publisher.resources :magazines do |magazine|
    magazine.resources :photos
  end
end

這將使得以下路由能夠被識別:

/publishers/1           ==> publisher_path(1)
/publishers/1/magazines ==> publisher_magazines_path(1)
/magazines/2            ==> magazine_path(2)
/magazines/2/photos     ==> magazines_photos_path(2)
/photos/3               ==> photo_path(3)

5.2 成員或集合路由的方法陣列

現在,您可以為新的成員或集合路由提供一個方法陣列。這樣可以解決當您需要處理多個動詞時,不得不將路由定義為接受任何動詞的麻煩。在Rails 2.2中,這是一個合法的路由聲明:

map.resources :photos, :collection => { :search => [:get, :post] }

5.3 具有特定操作的資源

默認情況下,當您使用 map.resources 創建一個路由時,Rails會為七個默認操作(index、show、create、new、edit、update和destroy)生成路由。但是,每個路由在應用程序中佔用內存,並導致Rails生成額外的路由邏輯。現在,您可以使用 :only:except 選項來微調Rails為資源生成的路由。您可以提供單個操作、操作陣列或特殊的 :all:none 選項。這些選項會被嵌套資源繼承。

map.resources :photos, :only => [:index, :show]
map.resources :products, :except => :destroy

5.4 其他Action Controller更改

  • 現在可以輕鬆地為路由請求引發的異常顯示自定義錯誤頁面
  • 默認情況下,HTTP Accept標頭已禁用。您應該優先使用格式化的URL(例如 /customers/1.xml)來指示您想要的格式。如果需要Accept標頭,可以使用 config.action_controller.use_accept_header = true 將其打開。
  • 基準測試數字現在以毫秒為單位報告,而不是秒的小數部分。
  • Rails現在支持僅HTTP的Cookie(並將其用於會話),這有助於在新版本的瀏覽器中減輕一些跨站腳本風險。
  • redirect_to 現在完全支持URI方案(因此,例如,您可以重定向到svn`ssh: URI)。
  • render 現在支持 :js 選項,以使用正確的MIME類型呈現純粹的JavaScript。
  • 請求偽造保護已經加強,僅適用於HTML格式的內容請求。
  • 如果傳遞的參數為nil,多態URL將更合理地處理。例如,使用nil日期調用 polymorphic_path([@project, @date, @area]) 將為您提供 project_area_path

    Action View

  • javascript_include_tagstylesheet_link_tag 支援新的 :recursive 選項,可以與 :all 一起使用,這樣你就可以用一行程式碼載入整個樹狀結構的檔案。

  • 內建的 Prototype JavaScript 函式庫已升級至版本 1.6.0.3。

  • RJS#page.reload 可以透過 JavaScript 重新載入瀏覽器的目前位置。

  • atom_feed 輔助方法現在接受 :instruct 選項,讓你可以插入 XML 處理指令。

6 Action Mailer

Action Mailer 現在支援郵件佈局。你可以通過提供相應名稱的佈局(例如,CustomerMailer 類預期使用 layouts/customer_mailer.html.erb)使你的 HTML 郵件和瀏覽器中的視圖一樣漂亮。

Action Mailer 現在內建支援 GMail 的 SMTP 伺服器,自動啟用 STARTTLS。這需要安裝 Ruby 1.8.7。

7 Active Support

Active Support 現在為 Rails 應用程式提供內建的記憶化支援、each_with_object 方法、委派的前綴支援和其他各種新的實用方法。

7.1 記憶化

記憶化是一種將方法初始化一次並將其值存儲起來以供重複使用的模式。你可能在自己的應用程式中使用過這種模式:

def full_name
  @full_name ||= "#{first_name} #{last_name}"
end

記憶化讓你以聲明式的方式處理這個任務:

extend ActiveSupport::Memoizable

def full_name
  "#{first_name} #{last_name}"
end
memoize :full_name

記憶化的其他功能包括 unmemoizeunmemoize_allmemoize_all 用於開啟或關閉記憶化。

7.2 each_with_object

each_with_object 方法提供了一種替代 inject 的方法,使用了從 Ruby 1.9 回溯的方法。它遍歷集合,將當前元素和記憶體傳遞給區塊。

%w(foo bar).each_with_object({}) { |str, hsh| hsh[str] = str.upcase } # => {'foo' => 'FOO', 'bar' => 'BAR'}

主要貢獻者:Adam Keys

7.3 帶前綴的委派

如果你從一個類委派行為到另一個類,現在你可以指定一個前綴,用於識別被委派的方法。例如:

class Vendor < ActiveRecord::Base
  has_one :account
  delegate :email, :password, :to => :account, :prefix => true
end

這將產生被委派的方法 vendor#account_emailvendor#account_password。你也可以指定自定義的前綴:

class Vendor < ActiveRecord::Base
  has_one :account
  delegate :email, :password, :to => :account, :prefix => :owner
end

這將產生被委派的方法 vendor#owner_emailvendor#owner_password。 主要貢獻者:Daniel Schierbeck

7.4 其他Active Support變更

  • ActiveSupport::Multibyte進行了大量更新,包括Ruby 1.9相容性修正。
  • 新增了ActiveSupport::Rescuable,允許任何類別使用rescue_from語法。
  • DateTime類別新增了past?today?future?,以便進行日期/時間比較。
  • Array#secondArray#fifth作為Array#[1]Array#[4]的別名。
  • Enumerable#many?封裝了collection.size > 1
  • Inflector#parameterize產生URL可用的版本,供to_param使用。
  • Time#advance支援小數天和週,例如1.7.weeks.ago1.5.hours.since等。
  • 包含的TzInfo庫已升級至0.3.12版本。
  • ActiveSupport::StringInquirer提供了一種漂亮的方式來測試字串的相等性:ActiveSupport::StringInquirer.new("abc").abc? => true

8 Railties

在Railties(Rails核心代碼)中,最大的變更是在config.gems機制中。

8.1 config.gems

為了避免部署問題並使Rails應用更加自包含,可以將Rails應用所需的所有gem副本放在/vendor/gems中。這個功能首次出現在Rails 2.1中,但在Rails 2.2中更加靈活和強大,可以處理gem之間的複雜依賴關係。Rails中的gem管理包括以下命令:

  • config/environment.rb文件中使用config.gem _gem_name_
  • 使用rake gems列出所有配置的gem,以及它們(和它們的依賴)是否已安裝、凍結或框架(框架gem是在執行gem依賴代碼之前由Rails加載的gem;這些gem無法凍結)
  • 使用rake gems:install將缺少的gem安裝到計算機上
  • 使用rake gems:unpack將所需的gem副本放入/vendor/gems
  • 使用rake gems:unpack:dependencies將所需的gem及其依賴關係的副本放入/vendor/gems
  • 使用rake gems:build構建任何缺少的原生擴展
  • 使用rake gems:refresh_specs將使用Rails 2.1創建的vendored gem與Rails 2.2的存儲方式保持一致

可以通過在命令行上指定GEM=_gem_name_來解壓縮或安裝單個gem。

8.2 其他Railties變更

  • 如果你是Thin網頁伺服器的粉絲,你會很高興知道script/server現在直接支援Thin。
  • script/plugin install &lt;plugin&gt; -r &lt;revision&gt;現在可以用於基於git和svn的插件。
  • script/console現在支援--debugger選項。
  • 在Rails源碼中包含了建立連續集成伺服器來構建Rails本身的指示。
  • rake notes:custom ANNOTATION=MYFLAG允許列出自定義註釋。
  • Rails.env封裝在StringInquirer中,這樣你就可以使用Rails.env.development?
  • 為了消除廢棄警告並正確處理gem依賴關係,Rails現在需要rubygems 1.3.1或更高版本。 已棄用 ----------

在此版本中,有一些舊代碼已被棄用:

  • Rails::SecretKeyGenerator 已被 ActiveSupport::SecureRandom 取代
  • render_component 已被棄用。如果需要此功能,可以使用 render_components 插件
  • 在渲染局部視圖時,隱式本地變量賦值已被棄用。

    def partial_with_implicit_local_assignment
      @customer = Customer.new("Marcel")
      render :partial => "customer"
    end
    

    以前,上述代碼在局部視圖 'customer' 內提供了一個名為 customer 的本地變量。現在,您應該通過 :locals 散列明確傳遞所有變量。

  • country_select 已被移除。請參閱 棄用頁面 以獲取更多信息和插件替代方案。

  • ActiveRecord::Base.allow_concurrency 不再起作用。

  • ActiveRecord::Errors.default_error_messages 已被棄用,建議使用 I18n.translate('activerecord.errors.messages')

  • 插值國際化的 %s%d 語法已被棄用。

  • String#chars 已被 String#mb_chars 取代。

  • 帶有小數月份或小數年份的持續時間已被棄用。請改用 Ruby 的核心 DateTime 類算術。

  • Request#relative_url_root 已被棄用。請改用 ActionController::Base.relative_url_root

9 貢獻者

發行說明由 Mike Gunderloy 編寫。

回饋

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

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

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

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

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