寫ruby一段時間以後,可能會著迷於這個框架的自由度
甚至還可以自行擴充框架本身
來達成想要滿足的商業邏輯
例如新手可能會將程式多次重複在專案各處
漸漸學習到可以將重複的部分整理到model或是service or view helper
如果這些都不滿足
有部分的功能,可以跨專案運用
那可以考慮拉出來成為一隻獨立的gem
或是試著複寫到ruby本身
比如說Time.methods
可以列出所有Time的方法,但是會包含上層繼承而來的方法
所以如果要看Time本身的方法,可以加參數false
Time.methods false
=> [:now, :at, :utc, :gm, :local, :mktime, :zone_offset, :parse, :strptime, :rfc2822, :rfc822, :httpdate, :xmlschema, :iso8601, :zone_default, :zone_default=, :zone, :zone=, :use_zone, :find_zone!, :find_zone, :===, :days_in_month, :current, :at_with_coercion, :at_without_coercion]
假設我今天有個需求,要計算生日
一開始可能會寫在member model裡面,例如
class Member
def years_old
#...先省略實作
end
end
這時取出任意一個Member實體,都可以用years_old方法
member = Member.find(1)
member.years_old
=> 18
理想上可以得到這樣的結果
但如果除了Member外,我有另外一個Model叫做Custom也需要計算生日
在Custom裡面也有一個一模一樣的方法,似乎就不是什麼高明之舉
class Member
def years_old
#...先省略實作
end
end
class Custom
def years_old
#一模一樣
end
end
這個時候有兩種做法,看實際運用狀況
可以整理到view helper或是service
如果是後者,比方說
#app/service/time_tool.rb
class TimeTool
def years_old(birthday)
#...略
end
end
那這時,上面兩個model就可以整理為
class Member
def years_old
TimeTool.new.years_old(birthday)
end
end
class Custom
def years_old
TimeTool.new.years_old(birthday)
end
end
等於把相同的部分,整理到Service當中,實現Dry(Don't Repeat Yourself)的精神
那假如更進一步,想要在任意的日期物件呼叫與今日的年份差距(生日)
可以再往上提一層,比方說
#app/models/date.rb
class Date
def self.years_old
#略
end
end
這邊要特別注意,在config/environments/development.rb
要改為true,不然不會生效config.eager_load = true
重啟console之後Date.methods false
就可以看到剛剛新增的方法:years_old
所以只要 birthday.class => Date
就可以直接使用這個方法,例如
m = Member.find(1)
m.birthday.years_old
=> 18
c = Custom.find(1)
c.birthday.years_old
=> 18
甚至任何日期,想要知道與今天相隔幾年,都可以直接使用這個方法
因為你定義在Date這個class裡面,所有Date或繼承Date的物件,都可以自由地使用這個方法
是不是更方便了呢