這個功能其實從 Rails 2 就有了(也許更早,我不太確定),不過我最近才有機會研究了一番,看的也是 Rails 3 的文件。

要在 model 裡面使用 serialize 有一個限制,就是該欄位必須是 text 格式,所以在玩這個功能之前請先 migrate 一個 text format 的 column 出來。

寫法如下:

class User < ActiveRecord::Base
  serialize :preferences
end

serialize 第一個參數是欄位名稱,第二個是 class 。可以有變化的地方在 class 這個參數,如果不給預設就是使用 YAML ,可以給 Array, Hash 甚至是自定的 class ,看你存什麼格式就會照著寫入該欄位內。

比方說接續上面的範例:

user = User.create(:preferences => { "background" => "black", "display" => large })
User.find(user.id).preferences # => { "background" => "black", "display" => large }

 

如果 class 不對,比方說格式指定 Hash ,你卻塞給他一個 Array ,那麼就會跳出 SerializationTypeMismatch 錯誤。

class User < ActiveRecord::Base
  serialize :preferences, Hash
end

user = User.create(:preferences => %w( one two three ))
User.find(user.id).preferences    # raises SerializationTypeMismatch

特別注意到,如果你使用一個 class ,那麼它會自動變成你這個 model 的 instance method ,非常的酷!

class User < ActiveRecord::Base
  serialize :preferences, OpenStruct
end

user = User.new
user.preferences.theme_color = "red"

 

最後,由於欄位需要做初始化的動作,可以在 migrate 時就指定預設值 "--- {}" ,但是 MySQL 5.x 會對 text 格式的欄位忽略預設值,因此建議作法是用 after_initialize callback ,去呼叫同名 method ,雖然會對 performance 會造成些微的影響,但可以避免一些錯誤出現。

def preferences 
  read_attribute(:preferences) || write_attribute(:preferences, {}) 
end

 

參考資料:

http://api.rubyonrails.org/classes/ActiveRecord/Base.html
THE RAILS 3 WAY

arrow
arrow

    笨笨小蟹 發表在 痞客邦 留言(1) 人氣()