你知道 Rails 何時須要用 require 嗎?
喜歡作者的文章嗎?馬上按「關注」,當作者發佈新文章時,思書™就會 email 通知您。
思書是公開的寫作平台,創新的多筆名寫作方式,能用不同的筆名探索不同的寫作內容,無限寫作創意,如果您喜歡寫作分享,一定要來試試! 《 加入思書》
思書™是自由寫作平台,本文為作者之個人意見。
給本文個喜歡
或不
關於作者
很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯
看看作者的其他文章
看看思書的其他文章
說實話,我寫了好久的 Rails 都搞不清楚何時須要加 require,又何時不須要,反正不會動的時候就加加看,會動就不管了,直到最近,一時興起,Hey,總要搞清楚吧,花了些時間,終於,算明白了,分享給大家,也留給自己幫助記憶。
先說什麼是 require
很簡單啦,就是當你要用一個外部的程式檔案時,你要先說這檔案在那裡,不然 Rails 怎麼會知道,如果你有寫 C,就跟 C 的 include 是一樣的啦,每一個電腦語言都有這種「納入」外部的程式檔案的方式,但是,這時,你會看到有兩種 require 的方式:
require '絕對路徑/target'
require 'target'
第一種問題不大,都有絕對路徑了,就一定是去指定的地方讀檔案。
第二種就有趣了,如果你細想,一定會好奇到底 Rails 會去那裡找檔案?
Rails Require 的預設路徑
原來,Rails 有預設路徑,就是
$LOAD_PATH
,它會告訴 Rails 遇到 Require 時,要去那裡找檔案,要查看,也很簡單,到 Rails console 中打:$LOAD_PATH
,你就可以看到一長串了。官網中也很清楚的說明了,可以用 set_load_path 去設定
$LOAD_PATH
,基本上,當 Rails 起始時,就會先將 vendor,lib,所有 app 下的目錄加入$LOAD_PATH
,及,任何你加在 config.load_paths 的目錄。實務上,大家很少會另外增加預設路徑,因為夠用了啦,Rails 人大多用 Gem,Gem 都會自動做 require,連 require 都不要寫,只有很少的情況下,你需要特別將外部的程式放入你的 app 中,就算要,光 lib 跟 vendor 就很夠放了,標準的 Rails 設定是希望你將外部程式加在 lib 的目錄中。
Require 是來外加的程式的,那如果你自己寫的程式呢,你是不是(早期)很會遇到以下這個錯誤:
啊~ NameError: uninitialized constant
什麼鬼啊,如果你是初學者,心裡一定會吶喊,名稱錯誤:未初始化的常數......
恭喜你,歡迎來了解 Rails 有名的 Auto Loading,Rails 的原設計就是「一定」要你照 Rails 的規矩寫,不能自己亂來,只要你乖乖的照 Rails 的規矩,你可以省很多事,例如:不需要 require。
來,我們來看一段碼,實務上,我們常將一切共用的碼,另外放在新增一個 services 目錄中,我們現在將以下這個示範碼放入,檔名叫「food_service.rb」:
再來,在 Rails console 中:
執行
food = FOodService.new
哇哈哈哈哈哈, 你又看到熟悉的錯誤:NameError: uninitialized constant FOodService,很無言,不用,你只要將上面的
class FOodService
改成class
FoodService
,在 Rails console 中在再:執行
food = FoodService.new
啊,會動了,為什麼?不為什麼,因為......
這就是 Rails 中有名的 Autoloading
在 Rails 中,檔名跟 Class 及 module 的名稱必須要依照 Rails 的規矩,你乖乖,Rails 也乖乖,以這個例子來說明,Rails 的規矩就是:
以上面的例子來說,如果你堅持 Class 的名稱就是要叫 FOodService,那你的檔名就必須是:f_ood_service.rb,不算難懂啦。
不管你喜不喜歡,這就是 Rails 的規矩,你要用 Rails 就得照做,不得反抗!這種叫「Auto Loading」的規矩,遍佈 Rails 中的每個角落,每一個 controller 及 model 都照這規矩,Rails 這樣做的目的只有一個,就是讓你不需要使用「require」,這很好,不然你光打 require 就會打到懷疑人生,一定會罵人,想想,一個網站幾十、上百個 class,我們都要謝謝 auto loading。
你覺得這 auto loading 很簡單嗎?好像不是,Rails 6 以後,改了一個新的「Zeitwerk」法,對應到以前的就叫「Classic」法,聽說新的方法比較執行緒安全 (Thread-safe),這個問題太難了,不重要,跳過,等碰到問題再說,我們要知道的是如何設定跟使用。
eager_load
當這個被設定成 true 時,所有在 eager_load_paths 指定的目錄中檔案,都會先被載入,不管你有沒有用到,而且更狠的是,載入後,就會把 auto loading 關掉,目的是要執行緒安全又有效率,所以,這不適合在 development 開發模式下用,你每變動一下名稱,就要重開,會煩死,自然,eager_load 只會在 production 模式下使用,
在 development 開發模式下,我們希望能快速的更改程式碼,這時,Rails 的 eager_load 在 config/environement/development.rb 的預設是 false 關掉, 這時,不管你怎麼變動名稱,Rails 都會嘗試找到它。
Rails 5 的 require 有問題
如果你用 Rails 5,又發現在 production 模式下,require 找不到 lib 下的檔案,這時你就需要將 lib 加到 config/application.rb 中的 eager_load_paths,如下:
config.eager_load_paths += %W(#{config.root}/lib)
Load code in libraries in Rails 5 — Load code in libraries in Rails 5. GitHub Gist: instantly share code, notes, and snippets.
Gist
上面的文章說明了理由,不理想,但是我覺得比將 lib 放在 app 下面好。
希望這篇文章對大家有幫助,說不定以後可以賣錢出書,哈哈哈哈!