小探 Rails ActiveSupport

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

Leave a Reply