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

紅寶鐵軌客
Join to follow...
Follow/Unfollow Writer: 紅寶鐵軌客
By following, you’ll receive notifications when this author publishes new articles.
Don't wait! Sign up to follow this writer.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.
寫程式中、折磨中、享受中 ......
886   0  
·
2020/03/21
·
5 mins read


 

說實話,我寫了好久的 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 下面好。

 

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

 

 


WriterShelf™ is a unique multiple pen name blogging and forum platform. Protect relationships and your privacy. Take your writing in new directions. ** Join WriterShelf**
WriterShelf™ is an open writing platform. The views, information and opinions in this article are those of the author.


Article info

This article is part of:
分類於:
標籤:
合計:1396字


Share this article:
About the Author

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




Join the discussion now!
Don't wait! Sign up to join the discussion.
WriterShelf is a privacy-oriented writing platform. Unleash the power of your voice. It's free!
Sign up. Join WriterShelf now! Already a member. Login to WriterShelf.