Update(2008/4/9): 這篇 RAILS RUBYISMS ADVENT也可以一看。
ActiveSupport 是 Rails 的工具箱。最近在看 Advanced Rails, O’Reilly 一書,有幾樣東西值得記上一筆:
JSON
我們有 Object#to_json,物件如 array,hash 等都可以呼叫 to_json 轉 JSON 格式,非常方便與 JavaScript 做銜接。
Blank
所有的物件都加上了 blank? 這個函式,回傳 true 如果是 1. 空字串 2. 只含空白的字串 3. false 4. nil 5. empty array [] 6. empty hash {}。所以別再寫 ( s.nil? || s.empty? ) 啦。
Class Attribute Accessors
可用宣告的方式定義 Class Attribute,如
class Foo cattr_accessor :bar self.bar = "" end
這樣會定義出來的 C.bar 即 @@bar
Class Inheritable Attributes
Class Attribute 是整個類別繼承體系共用,這在我們寫 ActiveRecord 相關 plugin 時非常不適用,因為所有的 model 都繼承自 ActiveRecord,但是各自又要有不同的 Class Attributes 值。最常見的使用狀況就是 plugin 了,model A 和 model B 都 include 某個 plugin,但是這個 plugin 的設定值要不一樣。拿大家都在用的 attactment_fu 舉例:
class UploadImage < ActiveRecord::Base has_attachment :content_type => :image, :storage => :file_system end
翻出 has_attachment 的 source code 你就看到這招了:
def has_attachment(options = {}) ...... class_inheritable_accessor :attachment_options self.attachment_options = options # 這裡的 self 指的是 UploadImage ...... end
除了 class_inheritable_accessor(syms) ,還有 class_inheritable_array(syms) 和class_inheritable_hash(*syms) 等。
Class Attribute Accessors 的原理可以請參考 class instance variables 這篇。
Date and Time conversions
不需要每次寫 Helper 用 strftime,我們可在 environment.rb 新增自訂的 format,例如
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!( :foo => '%m/%d %l:%M %p')
這樣就可以對 Time 物件呼叫 to_s(:foo),內建還有 :default, :short, :long, :db 等等。
alias_method_chain
在 Rails source code 十分常見:
alias_method_chain :target, :feature
等同於
alias_method :target_without_feature, :target alias_method :target, :target_with_feature
Delegation
將 methods 傳給另一個 object
class Account < ActiveRecord::Base has_one :foo delegate :free?, :to => :foo end
這樣 account.free? 就會呼叫 account.foo.free? 考慮 foo 可能 nil,我們可以多一個檢查:
delegate :free?, :to => "something.nil? ? false : something"
甚至兩層,假設 foo 有 bar:
delegate :free?, :to => "foo.bar"
這樣 account.free? 就會呼叫 account.foo.bar.free?
#Object#returning
讓你執行一些操作然後傳回:
returning(User.new) do |u| u.name = "Foo" end
#Object#with_options
最常用在 routes.rb,不過其實任意物件都可以用,他會將參數自動 merge 到 method call 的 hash 參數:
map.with_options( :controller => "people" ) do |p| p.root :action => "index" p.about :action => "about" end