← 上一章:使用套件(Gem)讓開發更有效率 下一章:Routes →
Model、View、Controller 三分天下
整個 Rails 專案是採用 Model、View、Controller(簡稱 MVC)的方式設計的。想當年,我在開發 PHP 專案的時候沒有這麼麻煩,在一個 .php 檔案就處理完查詢資料庫、展示資料等工作(那時候沒有使用其它框架),最多可能會把會共用的程式碼獨立在另一個檔案,然後 require
進來使用。所以在我剛開始學習 Rails 的時候一直有這個疑問,就是「為什麼 Rails 要搞這麼複雜?檔案分得這麼細要一直切換實在很麻煩耶!」
為什麼要這麼麻煩?
分工容易
整個專案拆解成 MVC 結構之後,雖然檔案變多、變分散了,但也因此更容易進行分工,當團隊人數增加,每個人可以在各自負責的部份進行開發,較不易互相衝突、干擾。
開發慣例
另一個好處,就是因為整個 Rails 專案都是遵循 MVC 的慣例結構,所以即使是不同程度的開發者寫出來的 Rails 專案,Controller 通常會放在 app/controllers
目錄裡,Model 應該也會放在 app/models
裡,不會有太大的差別。
圖解 MVC
我們用一張圖來說明 Rails 裡的 MVC 是怎麼運作的:
- 當有使用者輸入網址,連到你的網站的時候,第一關會遇到的是路徑對照表(Route,檔案:
config/routes.rb
)。 - 在這個路徑對照表裡,記錄著這個網站對外開放的路徑對照表。Rails 會根據使用者輸入的網址及參數,比對這個路徑對照表的資料,告訴你應該去找哪個 Controller 上的哪個 Action;或是如果在對照表裡查不到對應的資料,就會告訴你
HTTP 404
找不到頁面。 - 在 Controller 上通常會有一個以上的 Action,這些 Action 說穿了就是一般 Ruby 裡的方法(method)而已。透過路徑對照表,找到了對應的 Action,這個 Action 會決定要做什麼事。
- 舉例個子來說,在這個 Action 可能會需要查閱「目前所有的商品列表」,接著它就會去請 Model 幫忙查資料。
- Model 本身並不是資料庫,但它可以幫你把你跟 Model 說的「人話」轉成資料庫看得懂的資料庫查詢語言(Structured Query Language,簡稱 SQL)。
- 透過 SQL,Model 可以跟資料庫取得你想要的資料。
- Model 把這包資料交回 Controller/Action 手上。
- 雖然 Controller/Action 拿到資料了,但目前這包東西還沒美化、整理過,還不適合給使用者看,所以 Controller/Action 還需要跟 View 借一下畫面,讓資料更適合使用者閱讀。
- Controller/Action 把資料跟 View 的畫面組合,最後呈現給使用者看。
最後第 8 及第 9 步驟,大概就是「I have a data, I have a template, um!… 秀出查詢結果」之類的概念吧。
目錄結構
針對 Rails 的 Route + MVC 的組合,介紹一下這些角色在專案裡對應的目錄結構及慣例。
Route
跟 MVC 相比,Route 相對的較為單純,全部的路徑設定都放在 config/routes.rb
這個檔案裡:
config
目錄裡面除了 routes.rb
之外,基本上跟整個專案設定有關的幾乎都是放在這裡,例如 database.yml
就是專門用來設定資料庫連線資訊的地方。關於 Route 的使用會在下一篇做更詳細的介紹。
Controller
Controller 就是放在專案的 app/controllers
目錄裡:
通常每個 Controller 會有自己獨立的檔案,而且檔案的名字跟類別的名字是對得起來的。規則很簡單,就是「大寫字元改成底線加小寫」。舉例來說,如果類別的名稱叫做 PostsController
,檔案的名字就會是 posts_controller.rb
。
如果有興趣想知道這是怎麼做的,也可以進到 rails console
裡使用字串類別的 underscore
以及 camelcase
兩個方法來玩看看:
$ bin/rails console
Running via Spring preloader in process 38922
Loading development environment (Rails 5.1.1)
>> "PostsController".underscore
=> "posts_controller"
>> "UsersController".underscore
=> "users_controller"
>> "posts_controller".camelcase
=> "PostsController"
另外,如果你打開每個 Controller 的內容,會發現預設都是繼承自 ApplicationController
這個類別。根據前面的規則,這個檔案的檔名自然就是 application_controller.rb
了。
Model
跟 Model 相關的檔案都放在 app/models
目錄裡:
它的類別與檔名規則跟 Controller 是一樣的,例如 Post
Model,它的檔名是 post.rb
;如果是 UserStory
,則是 user_story.rb
,以此類推。
另外,如果資料庫中有 Model 相對應的資料表(Table)的話,資料表的命名慣例是「小寫 + 複數」。簡單整理如下:
Model 類別名稱 | 檔案名稱 | 資料表名稱 |
---|---|---|
User | user.rb | users |
Post | post.rb | posts |
ProductItem | product_item.rb | product_items |
資料表的命名慣例是可以修改的,但沒必要的話通常不會特別去改它,盡量維持 Rails 的「慣例優於設定」(CoC, Convention Over Configuration)的原則。
View
View 的工作主要是負責畫面輸出,通常是一群 HTML 之類的檔案,就放在 app/views/
目錄底下,而且預設會隨著 Controller 的名字集中放在某個資料夾:
舉例來說,跟 PostsController
相關的 View,就會放在 app/views/posts
目錄裡。如果執行的是 PostsController
的 index
Action,沒特別聲明 render 方法的話,預設會去找 app/views/posts/index.html.erb
這個檔案。
而這個 index.html.erb
的附檔名本身也是有特別意義的:
- 最後面的
erb
是 Embedded Ruby 的縮寫,表示這個檔案會由 Ruby 標準函式庫中的 ERB 樣版引擎進行解讀。你可以在這個檔案裡寫一些 Ruby 語法,例如陣列的each
或map
方法以及像是產生超連結的link_to
方法。 - 而中間的
html
表示這個檔案在被 ERB 樣版引擎處理後會被輸出成 HTML。
大概了解 Route 跟 MVC 的運作方式,以及每個角色的所在目錄後,下個章節就可以準備來寫一些簡單的程式碼,熟悉一下 Rails 開發的手感。
Comments