你知道 Rails 何時須要用 require 嗎?

紅寶鐵軌客
來關注...
關注/停止關注:紅寶鐵軌客
關注有什麼好處?:當作者有新文章發佈時,「思書」就會自動通知您,讓您更容易與作者互動。
現在就加入《思書》,你就可以關注本作者了!
《思書》是一個每個人的寫作與論壇平台,特有的隱私管理,讓你寫作不再受限,討論更深入真實,而且免費。 趕快來試試!
還未加入《思書》? 現在就登錄! 已經加入《思書》── 登入
寫程式中、折磨中、享受中 ......
886   0  
·
2020/03/21
·
5分鐘


 

說實話,我寫了好久的 Rails 都搞不清楚何時須要加 require,又何時不須要,反正不會動的時候就加加看,會動就不管了,直到最近,一時興起,Hey,總要搞清楚吧,花了些時間,終於,算明白了,分享給大家,也留給自己幫助記憶。

 

先說什麼是 require

很簡單啦,就是當你要用一個外部的程式檔案時,你要先說這檔案在那裡,不然 Rails 怎麼會知道,如果你有寫 C,就跟 C 的 include 是一樣的啦,每一個電腦語言都有這種「納入」外部的程式檔案的方式,但是,這時,你會看到有兩種 require 的方式:

  1. require '絕對路徑/target'
  2. 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」:

class FOodService

  def eat(food)
    puts "#{food}好吃"
  end

end

再來,在 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 的規矩就是:

  • 檔名 food_service.rb:為了避免作業系統對檔名大小寫辨識的問題,必須是全小寫,字與字間,用底線分隔,又稱「小寫的蛇式」命名法。
  • Class 或 Module 的名稱:必須對應檔名,但是,是用大寫的駱駝式,也就是字與字間不分隔,用大寫開頭區隔,所以,檔名 food_service.rb 對應的 Class 及 Module 名稱就是 FoodService。

以上面的例子來說,如果你堅持 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 下面好。

 

希望這篇文章對大家有幫助,說不定以後可以賣錢出書,哈哈哈哈!

 

 


喜歡作者的文章嗎?馬上按「關注」,當作者發佈新文章時,思書™就會 email 通知您。

思書是公開的寫作平台,創新的多筆名寫作方式,能用不同的筆名探索不同的寫作內容,無限寫作創意,如果您喜歡寫作分享,一定要來試試! 《 加入思書》

思書™是自由寫作平台,本文為作者之個人意見。




分享這篇文章:
關於作者

很久以前就是個「寫程式的」,其實,什麼程式都不熟⋯⋯
就,這會一點點,那會一點點⋯⋯




參與討論!
現在就加入《思書》,馬上參與討論!
《思書》是一個每個人的寫作與論壇平台,特有的隱私管理,用筆名來區隔你討論內容,讓你的討論更深入,而且免費。 趕快來試試!
還未加入《思書》? 現在就登錄! 已經加入《思書》── 登入


看看作者的其他文章


看看思書的其他文章



×
登入
申請帳號

需要幫助
關於思書

暗黑模式?
字體大小
成人內容未過濾
更改語言版本?