有使用過 Active Model
的朋友應該都知道,只要在 new 時傳入一包 params,他就會自動把每個 value 按照 key 塞進 object 裡。
For example:
class ArticleForm
include ActiveModel::Model
attr_accessor :title, :content
end
ArticleForm.new(title: '標題', content: '內容')
=> <ArticleForm:0x000000001260c608 @title="標題", @content="內容">
# 會得到擁有 @title="標題" 以及 @content="內容" 的 object
但你知道為什麼嗎?
這是因為,Active Model
本身的 initialize
會用到 assign_attributes
這個方法,把傳入的 params 一個個塞進去。
而這個功能其實是由 ActiveModel::AttributeAssignment
這包 module 提供的。
一般狀況下,如果我們的 initialize
想要做到一樣的效果,把 value 一個個傳進來,應該會寫成這樣:
class ArticleForm
def initialize(params = {})
@title = params[:title]
@content = params[:content]
.... # 有幾個 attribute ,就要寫多長
end
end
通常的做法都是這樣,一個個 assign 為 instance variable。
但隨著你的 service 日後不斷擴充,增加更多的 attr,這個 initialize
只會越來越長越來越亂,很難看。
如果你想要有 Active Model
可以自動傳入 params 的功能,但又嫌這 module 太大包,很多功能用不到,那你可以試試看 ActiveModel::AttributeAssignment
:
class ArticleForm
include ActiveModel::AttributeAssignment
attr_accessor *%i(title content ...) # 日後擴充 attr 只需要加在這邊就好
def initialize(params)
assign_attributes(params)
end
end
ArticleForm.new(title: '標題', content: '內容')
=> <ArticleForm:0x00007f987b08d890 @title="標題", @content="內容">
# 得到跟上面一樣的結果
甚至,如果你的 initialize
功能很單純只是要傳入的話,你甚至可以這樣,一行解決:
alias_method :initialize, :assign_attributes
這樣你的 code 就可以免掉很多重複的 assignment ,還你乾淨漂亮簡潔的 class!