接續昨天的介紹
因為時間的關係(?)
還只停留在皮毛的階段
今天要繼續為各位講解有關路由的一些技巧與觀念
另外關於設定路由時常犯的新手錯誤
也可以參考前作新手常犯的十種錯 2內的第八點:
『找不到路由』
本篇就不再重複。
昨天介紹了resources
的使用方法
事實上在專案裡,只有一層的情況反而少見
通常都會是複數嵌套的方式使用,例如:
resources :books do
resources :pages
end
會產生如下的路由:
Prefix Verb URI Pattern Controller#Action
book_pages GET /books/:book_id/pages(.:format) pages#index
POST /books/:book_id/pages(.:format) pages#create
new_book_page GET /books/:book_id/pages/new(.:format) pages#new
edit_book_page GET /books/:book_id/pages/:id/edit(.:format) pages#edit
book_page GET /books/:book_id/pages/:id(.:format) pages#show
PATCH /books/:book_id/pages/:id(.:format) pages#update
PUT /books/:book_id/pages/:id(.:format) pages#update
DELETE /books/:book_id/pages/:id(.:format) pages#destroy
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
共16種。
如果不會全部用到,可以用到昨天所提的only方法
只產生需要的部分,可以避免過於雜亂充滿無用的路由
技術上可以超過三層或更多
但實務上非常不建議這麼做,因為不好理解,中間也需要準備許多不必要的參數
以上圖為例,pages的update需要page_id與book_id
但實務上有page_id就可以取得page的實體,裡面一定會包含book_id
所以傳入的book_id也可以說是多餘的
這個狀況在三層以後會更為明顯
為了避免這個情況當然也可以用限制方法手刻
但rails其實也提供了一種很便捷地整理方法:
resources :books do
resources :pages, shallow: true
end
會產生如下(因為book的部分沒有變故略過)
Prefix Verb URI Pattern Controller#Action
book_pages GET /books/:book_id/pages(.:format) pages#index
POST /books/:book_id/pages(.:format) pages#create
new_book_page GET /books/:book_id/pages/new(.:format) pages#new
edit_page GET /pages/:id/edit(.:format) pages#edit
page GET /pages/:id(.:format) pages#show
PATCH /pages/:id(.:format) pages#update
PUT /pages/:id(.:format) pages#update
DELETE /pages/:id(.:format) pages#destroy
很清楚地發現
除了index,create,new
這三個方法因為無可避免地會用到book_id以外
其餘都只需要傳入page_id,整個路由都顯得相當清爽
這邊要特別注意
原本form如果update與create共用時
只需要傳入model本身就會自行判斷路由,在使用shallow後會因為URL所需的變數不同而導致錯誤
假設原本寫法如下:
<%= simple_form_for [@book, @page], method: method do |f| %>
新增時可以正常運作,但卻會因為update時已經不需要book_id而導致錯誤
解決方法是將url作為參數一起傳進去
無法繼續讓rails自行判斷
如果路由有重複使用的情況
可以使用concern來收納
例如
resources :messages do
resources :comments
end
resources :articles do
resources :comments
end
在messages與articles下面都有一模一樣的comments
可以整理如下:
concern :commentable do
resources :comments
end
resources :messages, concerns: :commentable
resources :articles, concerns: :commentable
出來的結果是相同的
最後要提供一個觀念
router設計是以簡單易懂為原則
目標是貼近企業邏輯,讓開發者與使用者容易理解
而不是盡量貼近原本設計的資料庫階層或正規化
新手一開始設計路由時,常常會侷限於model的型態
而無法展開手腳
其實路由是可以很靈活的變化
只要讓開發者與使用者能夠更一目了然就可以了!!
不需要拘泥於資料結構
希望大家都能寫出更簡潔易懂的路由囉 :)