延續前面基本的路徑設計,這篇會提到比較多種巢狀設計的方式。

巢狀設計方式

resources 方法裡面其實還可以在包 resources,在後面會提到 model 之間關連性,例如一個 User 可能會有很多 Articles,Route 可能會這樣寫:

1
2
3
4
5
Rails.application.routes.draw do
resources :users do
resource :articles
end
end

終端機輸入 $ rails routes -c articles 查詢路徑可以看到如下

1
2
3
4
5
6
7
8
            Prefix Verb   URI Pattern                             Controller#Action
new_user_articles GET /users/:user_id/articles/new(.:format) articles#new
edit_user_articles GET /users/:user_id/articles/edit(.:format) articles#edit
user_articles GET /users/:user_id/articles(.:format) articles#show
PATCH /users/:user_id/articles(.:format) articles#update
PUT /users/:user_id/articles(.:format) articles#update
DELETE /users/:user_id/articles(.:format) articles#destroy
POST /users/:user_id/articles(.:format) articles#create

路徑內就包含特定”使用者”與”文章”之間的關係,像是:
/users/1/articles/new => 使用者 1 號的空間新增文章
/users/2/articles/3/edit => 使用者 2 號的空間對 3 號文章做修改

你也可以繼續往下包 resources,但是建議是 2 層最多,在下去可能變得太冗長,像是這樣:
/users/Sean/articles/6/comments/3

Shallow

會使用到這個簡化方法主要是在一些 action 不需要用到上一層資源相關的 id 我們可以透過 shallow 去設計
像是下面這樣的狀況,要呈現留言板在文章內,index, new, create 這 3 種需要知道是針對哪篇文章進行留言或顯示所有留言,所以會要保留 article id,但是在 show, edit, update, destroy,不需要知道 article id,只要針對 comment id 就可以進行相關動作。

1
2
3
4
resources :articles do
resources :comments, only: [:index, :new, :create] # 這3種 action 需要標出 article id
end
resources :comments, only: [:show, :edit, :update, :destroy] # 這些不需要標出 article id
1
2
3
4
5
6
7
8
9
10
             Prefix Verb   URI Pattern                                  Controller#Action
article_comments GET /articles/:article_id/comments(.:format) comments#index
POST /articles/:article_id/comments(.:format) comments#create
new_article_comment GET /articles/:article_id/comments/new(.:format) comments#new
edit_comment GET /comments/:id/edit(.:format) comments#edit
comment GET /comments/:id(.:format) comments#show
PATCH /comments/:id(.:format) comments#update
PUT /comments/:id(.:format) comments#update
DELETE /comments/:id(.:format) comments#destroy

上面的寫法可以利用 shallow 來簡化如下,產生出來的路徑都是相同。

1
2
3
resources :articles do
resources :comments, shallow: true
end

collection 與 member

如果預設的路徑不夠使用,且層層包裹之中,又希望設計要或不要帶有前面一層的 id 可以這樣表示
collection => 沒有 id
member => 有 id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Rails.application.routes.draw do
resources :friends do
collection do
# /friends/confirmed
get :confirmed
end
member do
# /friends/:id/status
post :status
# /friends/:id/
delete :destroy
end
end
end

對應路徑如下:

1
2
3
4
5
6
7
8
9
10
11
12
           Prefix Verb   URI Pattern                   Controller#Action
confirmed_friends GET /friends/confirmed(.:format) friends#confirmed
status_friend POST /friends/:id/status(.:format) friends#status
friend DELETE /friends/:id(.:format) friends#destroy
friends GET /friends(.:format) friends#index
POST /friends(.:format) friends#create
new_friend GET /friends/new(.:format) friends#new
edit_friend GET /friends/:id/edit(.:format) friends#edit
GET /friends/:id(.:format) friends#show
PATCH /friends/:id(.:format) friends#update
PUT /friends/:id(.:format) friends#update
DELETE /friends/:id(.:format) friends#destroy

namespace 與 scope

namespace => 會讓後面指定的資源除了加到路徑上之外也多加到 prefix 及 controller 的名稱上
scope => 只有將資源加到路徑

1
2
3
4
5
6
7
8
9
Rails.application.routes.draw do
namespace :users do
resources :articles
end

scope :users do
resources :articles
end
end

產生路徑如下,可以看到兩種的差異在於用 namespace 的會影響到 prefix 及 controller 的設計,如果有這樣需求的就可以這樣使用,路徑是都一樣的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# namespace
Prefix Verb URI Pattern Controller#Action
users_articles GET /users/articles(.:format) users/articles#index
POST /users/articles(.:format) users/articles#create
new_users_article GET /users/articles/new(.:format) users/articles#new
edit_users_article GET /users/articles/:id/edit(.:format) users/articles#edit
users_article GET /users/articles/:id(.:format) users/articles#show
PATCH /users/articles/:id(.:format) users/articles#update
PUT /users/articles/:id(.:format) users/articles#update
DELETE /users/articles/:id(.:format) users/articles#destroy
----------------------------------------------------------------------------------------------
# scope
Prefix Verb URI Pattern Controller#Action
articles GET /users/articles(.:format) articles#index
POST /users/articles(.:format) articles#create
new_article GET /users/articles/new(.:format) articles#new
edit_article GET /users/articles/:id/edit(.:format) articles#edit
article GET /users/articles/:id(.:format) articles#show
PATCH /users/articles/:id(.:format) articles#update
PUT /users/articles/:id(.:format) articles#update
DELETE /users/articles/:id(.:format) articles#destroy

參考資料:

  1. 為你自己學 Ruby on Rails
  2. Rails Guide