更多資訊請見 rubyonrails.org:

由外而內的 Rails 路由

本指南涵蓋 Rails 路由中面向使用者的功能。

閱讀本指南後,您將了解

  • 如何解讀 config/routes.rb 中的程式碼。
  • 如何使用偏好的資源風格或 match 方法建構您自己的路由。
  • 如何宣告路由參數,這些參數會傳遞到控制器動作。
  • 如何使用路由輔助方法自動建立路徑和 URL。
  • 進階技術,例如建立約束和掛載 Rack 端點。

1 Rails 路由器的用途

Rails 路由器會根據 URL 路徑,將傳入的 HTTP 請求比對到 Rails 應用程式中的特定控制器動作。(它也可以轉發到 Rack 應用程式。)路由器也會根據路由器中設定的資源產生路徑和 URL 輔助方法。

1.1 將傳入的 URL 路由到程式碼

當您的 Rails 應用程式收到傳入的請求時,它會要求路由器將其比對到控制器動作(又稱方法)。例如,以下列傳入的請求為例

GET /users/17

如果第一個符合的路由是

get "/users/:id", to: "user#show"

該請求會比對到 UsersController 類別的 show 動作,且 params 雜湊中包含 { id: '17' }

當傳遞字串時,to: 選項預期使用 controller#action 格式。或者,您可以傳遞符號並使用 action: 選項,而不是 to:。您也可以傳遞不帶 # 的字串,在此情況下,會改用 controller: 選項,而非 to:。例如

get "/users/:id", controller: "users", action: :show

在指定路由時,Rails 會針對控制器名稱使用 snake_case。例如,如果您有一個名為 UserProfilesController 的控制器,您會將路由指定到 show 動作,如 user_profiles#show

1.2 從程式碼產生路徑和 URL

路由器會自動為您的應用程式產生路徑和 URL 輔助方法。使用這些方法,您可以避免硬式編碼路徑和 URL 字串。

例如,當定義下列路由時,可以使用 user_pathuser_url 輔助方法

get "/users/:id", to: "users#show", as: "user"

as: 選項用於為路由提供自訂名稱,此名稱會在產生 URL 和路徑輔助方法時使用。

假設您的應用程式在控制器中包含下列程式碼

@user = User.find(params[:id])

以及在對應視圖中包含此程式碼

<%= link_to 'User Record', user_path(@user) %>

路由器會從 user_path(@user) 產生路徑 /users/17。使用 user_path 輔助方法可讓您避免在視圖中硬式編碼路徑。如果您最終將路由移至不同的 URL,這會很有幫助,因為您不需要更新對應的視圖。

它也會產生 user_url,其用途類似。雖然 user_path 會產生相對 URL(例如 /users/17),但 user_url 會產生絕對 URL(例如上述範例中的 https://example.com/users/17)。

1.3 設定 Rails 路由器

路由位於 config/routes.rb 中。以下範例說明典型的 Rails 應用程式中的路由外觀。以下章節將說明此檔案中使用的不同路由輔助方法

Rails.application.routes.draw do
  resources :brands, only: [:index, :show] do
    resources :products, only: [:index, :show]
  end

  resource :basket, only: [:show, :update, :destroy]

  resolve("Basket") { route_for(:basket) }
end

由於這是一個常規的 Ruby 來源檔案,您可以使用 Ruby 的所有功能(例如條件和迴圈)來協助您定義路由。

包裝路由定義的 Rails.application.routes.draw do ... end 區塊是建立路由器 DSL(網域特定語言)範圍的必要區塊,不得刪除。

請小心 routes.rb 中的變數名稱,因為它們可能會與路由器的 DSL 方法衝突。

2 資源路由:Rails 預設值

資源路由可讓您快速宣告給定資源控制器的所有常見路由。例如,單次呼叫 resources 會宣告 indexshowneweditcreateupdatedestroy 動作的所有必要路由,而無需您單獨宣告每個路由。

2.1 Web 上的資源

瀏覽器會使用特定的 HTTP 動詞(例如 GETPOSTPATCHPUTDELETE)請求 URL,從 Rails 請求頁面。每個 HTTP 動詞都是對資源執行作業的請求。資源路由會將相關請求對應到單一控制器中的動作。

當您的 Rails 應用程式收到傳入的請求時

DELETE /photos/17

它會要求路由器將其對應到控制器動作。如果第一個符合的路由是

resources :photos

Rails 會將該請求分派到 PhotosControllerdestroy 動作,且 params 中包含 { id: '17' }

2.2 CRUD、動詞和動作

在 Rails 中,資源路由會提供從傳入請求(HTTP 動詞 + URL 的組合)到控制器動作的對應。依照慣例,每個動作通常會對應到您的資料上的特定 CRUD 作業。路由檔案中的單一項目,例如

resources :photos

在您的應用程式中建立七種不同的路由,全部對應到 PhotosController 的動作。

HTTP 動詞 路徑 Controller#Action (控制器#動作) 用途
GET /photos photos#index 顯示所有照片的清單
GET /photos/new photos#new 回傳用於建立新照片的 HTML 表單
POST /photos photos#create 建立新照片
GET /photos/:id photos#show 顯示特定照片
GET /photos/:id/edit photos#edit 回傳用於編輯照片的 HTML 表單
PATCH/PUT /photos/:id photos#update 更新特定照片
DELETE /photos/:id photos#destroy 刪除特定照片

由於路由器使用 HTTP 動詞路徑來匹配傳入的請求,四個 URL 可以對應到七個不同的控制器動作。例如,當動詞是 GET 時,相同的 photos/ 路徑會匹配到 photos#index,而當動詞是 POST 時則會匹配到 photos#create

routes.rb 檔案中,順序很重要。Rails 路由會按照指定的順序進行匹配。例如,如果您在 get 'photos/poll' 之上有 resources :photos,則 resources 行的 show 動作路由將會在 get 行之前匹配。如果您希望 photos/poll 路由先匹配,您需要將 get 行移到 resources上方

2.3 路徑和 URL 輔助方法

建立資源型路由也會在您的應用程式中的控制器和視圖中公開許多輔助方法。

例如,將 resources :photos 加入路由檔案會產生這些 _path 輔助方法

路徑輔助方法 回傳 URL
photos_path /photos
new_photo_path /photos/new
edit_photo_path(:id) /photos/:id/edit
photo_path(:id) /photos/:id

路徑輔助方法的參數(例如上面的 :id)會傳遞到產生的 URL,因此 edit_photo_path(10) 將回傳 /photos/10/edit

這些 _path 輔助方法中的每一個都有對應的 _url 輔助方法(例如 photos_url),它會回傳相同路徑,並加上目前的主機、端口和路徑前綴。

在 "_path" 和 "_url" 之前使用的前綴是路由名稱,可以透過查看 rails routes 命令輸出的「prefix」列來識別。若要了解更多資訊,請參閱下方的列出現有路由

2.4 同時定義多個資源

如果您需要為多個資源建立路由,您可以透過單次呼叫 resources 來定義它們,以節省一些輸入。

resources :photos, :books, :videos

以上是以下程式碼的簡寫:

resources :photos
resources :books
resources :videos

2.5 單數資源

有時,您會有一些使用者預期只有一個的資源(也就是說,沒有意義使用 index 動作來列出該資源的所有值)。在這種情況下,您可以使用 resource(單數)而不是 resources

以下資源型路由會在您的應用程式中建立六個路由,全部對應到 Geocoders 控制器。

resource :geocoder
resolve("Geocoder") { [:geocoder] }

透過記錄識別Geocoder 的實例轉換為單數路由,呼叫 resolve 是必要的。

以下是為單數資源建立的所有路由

HTTP 動詞 路徑 Controller#Action (控制器#動作) 用途
GET /geocoder/new geocoders#new 回傳用於建立地理編碼器的 HTML 表單
POST /geocoder geocoders#create 建立新的地理編碼器
GET /geocoder geocoders#show 顯示唯一一個地理編碼器資源
GET /geocoder/edit geocoders#edit 回傳用於編輯地理編碼器的 HTML 表單
PATCH/PUT /geocoder geocoders#update 更新唯一一個地理編碼器資源
DELETE /geocoder geocoders#destroy 刪除地理編碼器資源

單數資源對應到複數控制器。例如,geocoder 資源會對應到 GeocodersController

單數資源型路由會產生這些輔助方法

  • new_geocoder_path 回傳 /geocoder/new
  • edit_geocoder_path 回傳 /geocoder/edit
  • geocoder_path 回傳 /geocoder

如同複數資源,以 _url 結尾的相同輔助方法也會包含主機、端口和路徑前綴。

2.6 控制器命名空間和路由

在大型應用程式中,您可能希望在命名空間下組織控制器群組。例如,您可能在 Admin:: 命名空間下有一些控制器,這些控制器位於 app/controllers/admin 目錄中。您可以使用namespace區塊來路由到此類群組

namespace :admin do
  resources :articles
end

這會為每個 articlescomments 控制器建立一些路由。對於 Admin::ArticlesController,Rails 將會建立

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /admin/articles admin/articles#index admin_articles_path
GET /admin/articles/new admin/articles#new new_admin_article_path
POST /admin/articles admin/articles#create admin_articles_path
GET /admin/articles/:id admin/articles#show admin_article_path(:id)
GET /admin/articles/:id/edit admin/articles#edit edit_admin_article_path(:id)
PATCH/PUT /admin/articles/:id admin/articles#update admin_article_path(:id)
DELETE /admin/articles/:id admin/articles#destroy admin_article_path(:id)

請注意,在上面的範例中,所有路徑都具有 /admin 前綴,這是 namespace 的預設慣例。

2.6.1 使用模組

如果您想將 /articles(不帶 /admin 前綴)路由到 Admin::ArticlesController,您可以使用 scope 區塊來指定模組。

scope module: "admin" do
  resources :articles
end

另一種撰寫上述程式碼的方式:

resources :articles, module: "admin"

2.6.2 使用 Scope

或者,您也可以將 /admin/articles 路由到 ArticlesController(不帶 Admin:: 模組前綴)。您可以使用 scope 區塊來指定路徑。

scope "/admin" do
  resources :articles
end

另一種撰寫上述程式碼的方式:

resources :articles, path: "/admin/articles"

對於這些替代方案(路徑中沒有 /admin,模組前綴中沒有 Admin::),命名路由輔助方法與您不使用 scope 時保持不變。

在最後一種情況下,以下路徑會對應到 ArticlesController

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /admin/articles articles#index articles_path
GET /admin/articles/new articles#new new_article_path
POST /admin/articles articles#create articles_path
GET /admin/articles/:id articles#show article_path(:id)
GET /admin/articles/:id/edit articles#edit edit_article_path(:id)
PATCH/PUT /admin/articles/:id articles#update article_path(:id)
DELETE /admin/articles/:id articles#destroy article_path(:id)

如果您需要在 namespace 區塊內使用不同的控制器命名空間,您可以指定絕對控制器路徑,例如:get '/foo', to: '/foo#index'

2.7 巢狀資源

資源之間存在邏輯上的父子關係是很常見的。例如,假設您的應用程式包含這些模型

class Magazine < ApplicationRecord
  has_many :ads
end

class Ad < ApplicationRecord
  belongs_to :magazine
end

巢狀路由宣告可讓您在路由中捕獲此關係

resources :magazines do
  resources :ads
end

除了雜誌的路由之外,此宣告還會將廣告路由到 AdsController。以下是巢狀 ads 資源的所有路由

HTTP 動詞 路徑 Controller#Action (控制器#動作) 用途
GET /magazines/:magazine_id/ads ads#index 顯示特定雜誌的所有廣告清單
GET /magazines/:magazine_id/ads/new ads#new 回傳用於建立屬於特定雜誌的新廣告的 HTML 表單
POST /magazines/:magazine_id/ads ads#create 建立屬於特定雜誌的新廣告
GET /magazines/:magazine_id/ads/:id ads#show 顯示屬於特定雜誌的特定廣告
GET /magazines/:magazine_id/ads/:id/edit ads#edit 回傳用於編輯屬於特定雜誌的廣告的 HTML 表單
PATCH/PUT /magazines/:magazine_id/ads/:id ads#update 更新屬於特定雜誌的特定廣告
DELETE /magazines/:magazine_id/ads/:id ads#destroy 刪除屬於特定雜誌的特定廣告

這也會建立常用的路徑和 URL 路由輔助方法,例如 magazine_ads_urledit_magazine_ad_path。由於 ads 資源嵌套在 magazines 下,因此廣告 URL 需要雜誌。輔助方法可以將 Magazine 的實例作為第一個參數(edit_magazine_ad_path(@magazine, @ad))。

2.7.1 巢狀限制

您可以視需要將資源嵌套在其他嵌套資源中。例如

resources :publishers do
  resources :magazines do
    resources :photos
  end
end

在上面的範例中,應用程式將會識別如下的路徑

/publishers/1/magazines/2/photos/3

對應的路由輔助方法將為 publisher_magazine_photo_url,要求您在所有三個層級指定物件。如您所見,深度嵌套的資源可能會變得過於複雜且難以維護。

一般經驗法則是僅將資源嵌套 1 層。

2.7.2 淺層嵌套

避免深度嵌套(如上所述)的一種方法是在父項下限定範圍產生集合動作 - 以便了解階層結構,但不要嵌套成員動作。換句話說,僅使用最少量的資訊來建立路由,以唯一識別資源。

「成員」動作是指適用於單個資源且需要 ID 來識別其所作用的特定資源的動作,例如 showedit 等。「集合」動作是指對整個資源集進行操作的動作,例如 index

例如

resources :articles do
  resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]

在上面,我們使用 :only 選項,該選項會告訴 Rails 僅建立指定的路由。此想法在描述性路由和深度嵌套之間取得了平衡。有一種簡寫語法可以透過 :shallow 選項來實現這一點

resources :articles do
  resources :comments, shallow: true
end

這將產生與第一個範例完全相同的路由。您也可以在父資源中指定 :shallow 選項,在這種情況下,所有嵌套資源都將是淺層的

resources :articles, shallow: true do
  resources :comments
  resources :quotes
end

上面的文章資源將產生以下路由

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /articles/:article_id/comments(.:format) comments#index article_comments_path
POST /articles/:article_id/comments(.:format) comments#create article_comments_path
GET /articles/:article_id/comments/new(.:format) comments#new new_article_comment_path
GET /comments/:id/edit(.:format) comments#edit edit_comment_path
GET /comments/:id(.:format) comments#show comment_path
PATCH/PUT /comments/:id(.:format) comments#update comment_path
DELETE /comments/:id(.:format) comments#destroy comment_path
GET /articles/:article_id/quotes(.:format) quotes#index article_quotes_path
POST /articles/:article_id/quotes(.:format) quotes#create article_quotes_path
GET /articles/:article_id/quotes/new(.:format) quotes#new new_article_quote_path
GET /quotes/:id/edit(.:format) quotes#edit edit_quote_path
GET /quotes/:id(.:format) quotes#show quote_path
PATCH/PUT /quotes/:id(.:format) quotes#update quote_path
DELETE /quotes/:id(.:format) quotes#destroy quote_path
GET /articles(.:format) articles#index articles_path
POST /articles(.:format) articles#create articles_path
GET /articles/new(.:format) articles#new new_article_path
GET /articles/:id/edit(.:format) articles#edit edit_article_path
GET /articles/:id(.:format) articles#show article_path
PATCH/PUT /articles/:id(.:format) articles#update article_path
DELETE /articles/:id(.:format) articles#destroy article_path

帶有區塊的 shallow 方法會在其中建立範圍,其中每個嵌套都是淺層的。這會產生與上一個範例相同的路由

shallow do
  resources :articles do
    resources :comments
    resources :quotes
  end
end

有兩個選項可以與 scope 一起使用來自訂淺層路由 - :shallow_path:shallow_prefix

shallow_path 選項會為成員路徑加上給定參數的前綴

scope shallow_path: "sekret" do
  resources :articles do
    resources :comments, shallow: true
  end
end

此處的 comments 資源將為其產生以下路由

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /articles/:article_id/comments(.:format) comments#index article_comments_path
POST /articles/:article_id/comments(.:format) comments#create article_comments_path
GET /articles/:article_id/comments/new(.:format) comments#new new_article_comment_path
GET /sekret/comments/:id/edit(.:format) comments#edit edit_comment_path
GET /sekret/comments/:id(.:format) comments#show comment_path
PATCH/PUT /sekret/comments/:id(.:format) comments#update comment_path
DELETE /sekret/comments/:id(.:format) comments#destroy comment_path

:shallow_prefix 選項會將指定參數新增至 _path_url 路由輔助方法

scope shallow_prefix: "sekret" do
  resources :articles do
    resources :comments, shallow: true
  end
end

此處的 comments 資源將為其產生以下路由

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /articles/:article_id/comments(.:format) comments#index article_comments_path
POST /articles/:article_id/comments(.:format) comments#create article_comments_path
GET /articles/:article_id/comments/new(.:format) comments#new new_article_comment_path
GET /comments/:id/edit(.:format) comments#edit edit_sekret_comment_path
GET /comments/:id(.:format) comments#show sekret_comment_path
PATCH/PUT /comments/:id(.:format) comments#update sekret_comment_path
DELETE /comments/:id(.:format) comments#destroy sekret_comment_path

2.8 路由關注點

路由關注點可讓您宣告可以在其他資源中重複使用的通用路由。若要定義關注點,請使用 concern 區塊。

concern :commentable do
  resources :comments
end

concern :image_attachable do
  resources :images, only: :index
end

這些關注點可用於資源中,以避免程式碼重複,並在路由之間共享行為

resources :messages, concerns: :commentable

resources :articles, concerns: [:commentable, :image_attachable]

以上程式碼等同於:

resources :messages do
  resources :comments
end

resources :articles do
  resources :comments
  resources :images, only: :index
end

您也可以在 scopenamespace 區塊中呼叫 concerns,以取得與上述相同的結果。例如

namespace :messages do
  concerns :commentable
end

namespace :articles do
  concerns :commentable
  concerns :image_attachable
end

2.9 從物件建立路徑和 URL

除了使用路由輔助方法外,Rails 也可以從參數陣列建立路徑和 URL。例如,假設您有這一組路由

resources :magazines do
  resources :ads
end

當使用 magazine_ad_path 時,您可以傳入 MagazineAd 的實例,而不是數值 ID。

<%= link_to 'Ad details', magazine_ad_path(@magazine, @ad) %>

產生的路徑將會類似 /magazines/5/ads/42

您也可以使用 url_for 搭配物件陣列來取得上述路徑,如下所示

<%= link_to 'Ad details', url_for([@magazine, @ad]) %>

在這種情況下,Rails 會判斷 @magazine 是一個 Magazine 物件,而 @ad 是一個 Ad 物件,因此會使用 magazine_ad_path 輔助方法。一個更簡短的方式來寫 link_to 是直接指定物件,而不是完整的 url_for 呼叫。

<%= link_to 'Ad details', [@magazine, @ad] %>

如果您只想連結到一本雜誌

<%= link_to 'Magazine details', @magazine %>

對於其他動作,您需要將動作名稱插入到陣列的第一個元素,例如 edit_magazine_ad_path

<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %>

這允許您將模型的實例視為 URL,這是使用資源風格的一個關鍵優勢。

為了自動從諸如 [@magazine, @ad] 的物件衍生路徑和 URL,Rails 會使用 ActiveModel::NamingActiveModel::Conversion 模組中的方法。具體來說,@magazine.model_name.route_key 會回傳 magazines,而 @magazine.to_param 會回傳模型 id 的字串表示。因此,對於 [@magazine, @ad] 物件,產生的路徑可能會像 /magazines/1/ads/42

2.10 新增更多 RESTful 路由

您不僅限於 RESTful 路由預設建立的七個路由。您可以新增其他應用於集合或集合中個別成員的路由。

以下章節描述如何新增成員路由和集合路由。術語 member 指的是作用於單一元素的路由,例如 showupdatedestroy。術語 collection 指的是作用於多個元素或元素集合的路由,例如 index 路由。

2.10.1 新增成員路由

您可以將 member 區塊新增到資源區塊中,如下所示

resources :photos do
  member do
    get "preview"
  end
end

/photos/1/preview 的傳入 GET 請求將會路由到 PhotosControllerpreview 動作。資源 ID 值將在 params[:id] 中可用。它也會建立 preview_photo_urlpreview_photo_path 輔助方法。

member 區塊中,每個路由定義都會指定 HTTP 動詞(在上面的例子中是使用 get 'preview'get)。除了 get,您還可以使用 patchputpostdelete

如果您沒有多個 member 路由,您也可以將 :on 傳遞給路由,從而消除區塊

resources :photos do
  get "preview", on: :member
end

您也可以省略 :on 選項,這將建立相同的成員路由,只是資源 ID 值將在 params[:photo_id] 中可用,而不是 params[:id]。路由輔助方法也會從 preview_photo_urlpreview_photo_path 重新命名為 photo_preview_urlphoto_preview_path

2.10.2 新增集合路由

要為集合新增路由,請使用 collection 區塊

resources :photos do
  collection do
    get "search"
  end
end

這會讓 Rails 能夠識別諸如 /photos/search 的路徑(使用 GET),並路由到 PhotosControllersearch 動作。它也會建立 search_photos_urlsearch_photos_path 路由輔助方法。

就像成員路由一樣,您可以將 :on 傳遞給路由

resources :photos do
  get "search", on: :collection
end

如果您使用符號作為第一個位置引數定義其他資源路由,請注意它不等同於使用字串。符號推斷控制器動作,而字串推斷路徑。

2.10.3 為其他新的動作新增路由

要使用 :on 快捷方式新增替代的新動作

resources :comments do
  get "preview", on: :new
end

這會讓 Rails 能夠識別諸如 /comments/new/preview 的路徑(使用 GET),並路由到 CommentsControllerpreview 動作。它也會建立 preview_new_comment_urlpreview_new_comment_path 路由輔助方法。

如果您發現自己為資源路由新增了許多額外的動作,現在該停下來問問自己是否正在偽裝另一個資源的存在。

可以自訂由 resources 產生的預設路由和輔助方法,請參閱自訂資源路由章節以了解更多資訊。

3 非資源路由

除了使用 resources 進行資源路由外,Rails 還強大支援將任意 URL 路由到動作。您不會獲得由資源路由自動產生的路由群組。相反地,您需要在應用程式內單獨設定每個路由。

雖然您通常應該使用資源路由,但在某些情況下,非資源路由更合適。如果它不適合,則無需嘗試將應用程式的每個部分都強行納入資源框架中。

非資源路由的一個例子是將現有的舊 URL 映射到新的 Rails 動作。

3.1 綁定參數

當您設定一般路由時,您會提供一系列符號,Rails 會將這些符號映射到傳入的 HTTP 請求的部分。例如,考慮以下路由

get "photos(/:id)", to: "photos#display"

如果此路由處理對 /photos/1 的傳入 GET 請求,則結果將是調用 PhotosControllerdisplay 動作,並將最終參數 "1" 作為 params[:id] 提供。此路由也會將傳入的 /photos 請求路由到 PhotosController#display,因為 :id 是一個可選參數,在上例中以括號表示。

3.2 動態區段

您可以在一般路由中設定任意數量的動態區段。任何區段都將作為 params 的一部分提供給動作。如果您設定以下路由

get "photos/:id/:user_id", to: "photos#show"

此路由將回應諸如 /photos/1/2 的路徑。params 雜湊將會是 { controller: 'photos', action: 'show', id: '1', user_id: '2' }。

預設情況下,動態區段不接受點 - 這是因為點用作格式化路由的分隔符號。如果您需要在動態區段中使用點,請新增一個覆蓋此行為的約束 – 例如,id: /[^\/]+/ 允許任何不是斜線的字元。

3.3 靜態區段

您可以透過不在區段前加上冒號來指定靜態區段來建立路由

get "photos/:id/with_user/:user_id", to: "photos#show"

此路由將回應諸如 /photos/1/with_user/2 的路徑。在這種情況下,params 將會是 { controller: 'photos', action: 'show', id: '1', user_id: '2' }

3.4 查詢字串

params 也將包含查詢字串中的任何參數。例如,對於以下路由

get "photos/:id", to: "photos#show"

/photos/1?user_id=2 的傳入 GET 請求將會像往常一樣分派到 PhotosController 類別的 show 動作,而 params 雜湊將會是 { controller: 'photos', action: 'show', id: '1', user_id: '2' }

3.5 定義預設參數

您可以透過為 :defaults 選項提供雜湊來定義路由中的預設值。這甚至適用於您未指定為動態區段的參數。例如

get "photos/:id", to: "photos#show", defaults: { format: "jpg" }

Rails 會將 photos/12PhotosControllershow 動作匹配,並將 params[:format] 設定為 "jpg"

您也可以使用 defaults 區塊來定義多個項目的預設值

defaults format: :json do
  resources :photos
  resources :articles
end

您無法透過查詢參數覆蓋預設值 - 這是為了安全原因。唯一可以覆蓋的預設值是透過 URL 路徑中的替代來覆蓋的動態區段。

3.6 命名路由

您可以使用 :as 選項來指定任何路由的名稱,該名稱將由 _path_url 輔助方法使用

get "exit", to: "sessions#destroy", as: :logout

這會在您的應用程式中建立 logout_pathlogout_url 作為路由輔助方法。呼叫 logout_path 將會回傳 /exit

您也可以透過將自訂路由定義放在資源定義「之前」來使用 as 覆蓋由 resources 定義的路由輔助方法名稱,如下所示

get ":username", to: "users#show", as: :user
resources :users

這會定義一個 user_path 輔助方法,該方法將匹配 /:username (例如 /jane)。在 UsersControllershow 動作中,params[:username] 將會包含使用者的使用者名稱。

3.7 HTTP 動詞約束

一般來說,您應該使用 getpostputpatchdelete 方法來將路由約束為特定動詞。有一個 match 方法,您可以使用 :via 選項一次匹配多個動詞

match "photos", to: "photos#show", via: [:get, :post]

上面的路由匹配對 PhotosControllershow 動作的 GET 和 POST 請求。

您可以使用 via: :all 將所有動詞匹配到特定路由

match "photos", to: "photos#show", via: :all

GETPOST 請求都路由到單一動作具有安全性隱患。例如,GET 動作不會檢查 CSRF 權杖(因此從 GET 請求寫入資料庫不是一個好主意。如需更多資訊,請參閱安全指南)。一般來說,除非您有充分的理由,否則請避免將所有動詞路由到單一動作。

3.8 區段約束

您可以使用 :constraints 選項來強制執行動態區段的格式

get "photos/:id", to: "photos#show", constraints: { id: /[A-Z]\d{5}/ }

上面的路由定義要求 id 的長度為 5 個字母數字字元。因此,此路由將匹配諸如 /photos/A12345 的路徑,但不匹配 /photos/893。您可以使用更簡潔的方式來表達相同的路由

get "photos/:id", to: "photos#show", id: /[A-Z]\d{5}/

:constraints 選項採用正規表示式(以及任何回應 matches? 方法的物件),但限制是不能使用正規表示式錨點。例如,以下路由將無法運作

get "/:id", to: "articles#show", constraints: { id: /^\d/ }

然而,請注意,您不需要使用錨點,因為所有路由都以開始和結束位置為錨點。

例如

get "/:id", to: "articles#show", constraints: { id: /\d.+/ }
get "/:username", to: "users#show"

上述路由允許共用根命名空間,並且

  • 將總是數字開頭的路由路徑,例如 /1-hello-world,導向帶有 id 值的 articles
  • 將從不以數字開頭的路由路徑,例如 /david,導向帶有 username 值的 users

3.9 基於請求的約束

您還可以根據 Request 物件 上任何返回 String 的方法來約束路由。

您指定基於請求的約束方式與指定區段約束的方式相同。例如:

get "photos", to: "photos#index", constraints: { subdomain: "admin" }

將匹配路徑導向 admin 子網域的傳入請求。

您也可以使用 constraints 區塊來指定約束

namespace :admin do
  constraints subdomain: "admin" do
    resources :photos
  end
end

將匹配類似 https://admin.example.com/photos 的請求。

請求約束的工作原理是,呼叫 Request 物件 上與雜湊鍵同名的方法,然後將回傳值與雜湊值進行比較。例如:constraints: { subdomain: 'api' } 將如預期匹配 api 子網域。但是,使用符號 constraints: { subdomain: :api } 將不會匹配,因為 request.subdomain 會回傳 'api' 字串。

約束值應符合對應的 Request 物件方法回傳類型。

format 約束有一個例外,雖然它是 Request 物件上的方法,但它也是每個路徑上隱式的可選參數。區段約束具有優先權,並且僅當通過雜湊強制執行時才會應用 format 約束。例如,get 'foo', constraints: { format: 'json' } 將匹配 GET /foo,因為格式預設為可選。

您可以像在 get 'foo', constraints: lambda { |req| req.format == :json } 中一樣使用 lambda,僅匹配明確的 JSON 請求的路由。

3.10 進階約束

如果您有更進階的約束,您可以提供一個回應 matches? 的物件,供 Rails 使用。假設您想要將受限清單上的所有使用者路由到 RestrictedListController。您可以這樣做:

class RestrictedListConstraint
  def initialize
    @ips = RestrictedList.retrieve_ips
  end

  def matches?(request)
    @ips.include?(request.remote_ip)
  end
end

Rails.application.routes.draw do
  get "*path", to: "restricted_list#index",
    constraints: RestrictedListConstraint.new
end

您也可以將約束指定為 lambda

Rails.application.routes.draw do
  get "*path", to: "restricted_list#index",
    constraints: lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) }
end

matches? 方法和 lambda 都會收到 request 物件作為參數。

3.10.1 區塊形式的約束

您可以在區塊形式中指定約束。當您需要將相同的規則套用到多個路由時,這非常有用。例如:

class RestrictedListConstraint
  # ...Same as the example above
end

Rails.application.routes.draw do
  constraints(RestrictedListConstraint.new) do
    get "*path", to: "restricted_list#index"
    get "*other-path", to: "other_restricted_list#index"
  end
end

您也可以使用 lambda

Rails.application.routes.draw do
  constraints(lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) }) do
    get "*path", to: "restricted_list#index"
    get "*other-path", to: "other_restricted_list#index"
  end
end

3.11 通配符區段

路由定義可以包含一個通配符區段,它是以星號開頭的區段,例如 *other

get "photos/*other", to: "photos#unknown"

通配符區段允許所謂的「路由全域匹配」,這是一種指定特定參數 (上述的 *other) 與路由的剩餘部分匹配的方式。

因此,上面的路由將匹配 photos/12/photos/long/path/to/12,並將 params[:other] 設定為 "12""long/path/to/12"

通配符區段可以出現在路由中的任何位置。例如:

get "books/*section/:title", to: "books#show"

將匹配 books/some/section/last-words-a-memoir,其中 params[:section] 等於 'some/section',而 params[:title] 等於 'last-words-a-memoir'

從技術上講,一個路由甚至可以有多個通配符區段。匹配器會按照它們出現的順序將區段指派給參數。例如:

get "*a/foo/*b", to: "test#index"

將匹配 zoo/woo/foo/bar/baz,其中 params[:a] 等於 'zoo/woo',而 params[:b] 等於 'bar/baz'

3.12 格式區段

給定此路由定義

get "*pages", to: "pages#show"

透過請求 '/foo/bar.json',您的 params[:pages] 將等於 'foo/bar',且請求格式為 JSON,位於 params[:format] 中。

format 的預設行為是,如果包含在 URL 中,Rails 會自動從 URL 中擷取並將其包含在 params[:format] 中,但 format 不是 URL 中必要的。

如果您想要匹配沒有明確格式的 URL,並忽略包含格式副檔名的 URL,您可以提供 format: false,如下所示:

get "*pages", to: "pages#show", format: false

如果您想要使格式區段成為強制性的,因此不能省略,您可以提供 format: true,如下所示:

get "*pages", to: "pages#show", format: true

3.13 重定向

您可以使用路由中的 redirect 輔助方法,將任何路徑重定向到任何其他路徑

get "/stories", to: redirect("/articles")

您也可以重複使用匹配中的動態區段,以重定向到該路徑

get "/stories/:name", to: redirect("/articles/%{name}")

您也可以提供一個區塊給 redirect,它會接收符號化的路徑參數和請求物件

get "/stories/:name", to: redirect { |path_params, req| "/articles/#{path_params[:name].pluralize}" }
get "/stories", to: redirect { |path_params, req| "/articles/#{req.subdomain}" }

請注意,預設重定向是 301「永久移動」重定向。請記住,某些網頁瀏覽器或 Proxy 伺服器會快取此類型的重定向,導致舊頁面無法存取。您可以使用 :status 選項來變更回應狀態

get "/stories/:name", to: redirect("/articles/%{name}", status: 302)

在所有這些情況下,如果您沒有提供主機 (http://www.example.com),Rails 將從目前的請求中取得這些詳細資訊。

3.14 路由到 Rack 應用程式

您可以使用任何 Rack 應用程式作為匹配器的端點,而不是將 :to 指定為類似 'articles#index' 的字串,對應到 ArticlesController 類別中的 index 方法

match "/application.js", to: MyRackApp, via: :all

只要 MyRackApp 回應 call 並回傳 [status, headers, body],路由器就不會知道 Rack 應用程式與控制器動作之間的差異。這是一個 via: :all 的適當用法,因為您會希望允許您的 Rack 應用程式處理所有動詞。

一個有趣的小知識 - 'articles#index' 會展開成 ArticlesController.action(:index),它會回傳一個有效的 Rack 應用程式。

由於 procs/lambdas 是回應 call 的物件,您可以內嵌實作非常簡單的路由 (例如,用於健康檢查),類似這樣:get '/health', to: ->(env) { [204, {}, ['']] }

如果您將 Rack 應用程式指定為匹配器的端點,請記住,該路由在接收應用程式中將保持不變。使用以下路由,您的 Rack 應用程式應預期路由為 /admin

match "/admin", to: AdminApp, via: :all

如果您希望您的 Rack 應用程式在根路徑接收請求,請使用 mount

mount AdminApp, at: "/admin"

3.15 使用 root

您可以使用 root 方法指定 Rails 應該將 '/' 路由到哪裡

root to: "pages#main"
root "pages#main" # shortcut for the above

您通常將 root 路由放在檔案的頂部,以便可以先匹配它。

預設情況下,root 路由主要處理 GET 請求。但可以將其設定為處理其他動詞 (例如:root "posts#index", via: :post)

您也可以在命名空間和範圍內使用 root

root to: "home#index"

namespace :admin do
  root to: "admin#index"
end

以上程式碼會將 /admin 匹配到 AdminControllerindex 動作,並將 / 匹配到 HomeControllerindex 動作。

3.16 Unicode 字元路由

您可以直接指定 Unicode 字元路由。例如:

get "こんにちは", to: "welcome#index"

3.17 直接路由

您可以透過呼叫 direct 來建立自訂 URL 輔助方法。例如:

direct :homepage do
  "https://rubyonrails.org"
end

# >> homepage_url
# => "https://rubyonrails.org"

區塊的回傳值必須是 url_for 方法的有效參數。因此,您可以傳遞有效的字串 URL、雜湊、陣列、Active Model 執行個體或 Active Model 類別。

direct :commentable do |model|
  [ model, anchor: model.dom_id ]
end
direct :main do
  { controller: "pages", action: "index", subdomain: "www" }
end

# >> main_url
# => "http://www.example.com/pages"

3.18 使用 resolve

resolve 方法允許自訂模型的多型對應。例如:

resource :basket

resolve("Basket") { [:basket] }
<%= form_with model: @basket do |form| %>
  <!-- basket form -->
<% end %>

這將產生單數 URL /basket,而不是通常的 /baskets/:id

4 自訂資源路由

雖然 resources 產生的預設路由和輔助方法通常可以很好地為您服務,但您可能需要以某種方式自訂它們。Rails 允許多種不同的方式來自訂資源路由和輔助方法。本節將詳細介紹可用的選項。

4.1 指定要使用的控制器

:controller 選項可讓您明確指定要用於資源的控制器。例如:

resources :photos, controller: "images"

將識別以 /photos 開頭的傳入路徑,但路由到 Images 控制器

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /photos images#index photos_path
GET /photos/new images#new new_photo_path
POST /photos images#create photos_path
GET /photos/:id images#show photo_path(:id)
GET /photos/:id/edit images#edit edit_photo_path(:id)
PATCH/PUT /photos/:id images#update photo_path(:id)
DELETE /photos/:id images#destroy photo_path(:id)

對於命名空間控制器,您可以使用目錄表示法。例如:

resources :user_permissions, controller: "admin/user_permissions"

這將路由到 Admin::UserPermissionsController 執行個體。

僅支援目錄表示法。不支援使用 Ruby 常數表示法 (例如,controller: 'Admin::UserPermissions') 指定控制器。

4.2 指定 id 的約束

您可以使用 :constraints 選項來指定隱含 id 的必要格式。例如:

resources :photos, constraints: { id: /[A-Z][A-Z][0-9]+/ }

此宣告會將 :id 參數限制為符合給定的正規表示式。路由器將不再將 /photos/1 匹配到此路由。相反,/photos/RR27 將匹配。

您可以使用區塊形式來指定要套用到多個路由的單一約束

constraints(id: /[A-Z][A-Z][0-9]+/) do
  resources :photos
  resources :accounts
end

您也可以在此內容中使用非資源路由區段中可用的更進階約束

預設情況下,:id 參數不接受點 - 這是因為點用作格式化路由的分隔符。如果您需要在 :id 中使用點,請新增覆蓋此行為的約束 - 例如,id: /[^\/]+/ 允許任何非斜線的字元。

4.3 覆寫具名路由輔助方法

:as 選項可讓您覆寫路由輔助方法的預設命名。例如:

resources :photos, as: "images"

這將匹配 /photos 並像往常一樣將請求路由到 PhotosController但是使用 :as 選項的值將輔助方法命名為 images_path 等,如圖所示

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /photos photos#index images_path
GET /photos/new photos#new new_image_path
POST /photos photos#create images_path
GET /photos/:id photos#show image_path(:id)
GET /photos/:id/edit photos#edit edit_image_path(:id)
PATCH/PUT /photos/:id photos#update image_path(:id)
DELETE /photos/:id photos#destroy image_path(:id)

4.4 重新命名 newedit 路徑名稱

:path_names 選項可讓您覆寫路徑中預設的 newedit 區段。例如:

resources :photos, path_names: { new: "make", edit: "change" }

這將允許諸如 /photos/make/photos/1/change 之類的路徑,而不是 /photos/new/photos/1/edit

此選項不會變更路由輔助方法和控制器動作名稱。顯示的兩個路徑將具有 new_photo_pathedit_photo_path 輔助方法,並且仍然路由到 newedit 動作。

也可以使用 scope 區塊為您的所有路由統一變更此選項

scope path_names: { new: "make" } do
  # rest of your routes
end

4.5 使用 :as 為具名路由輔助方法加上前綴

你可以使用 :as 選項,為 Rails 為路由產生的具名路由輔助方法加上前綴。使用這個選項可以避免在使用路徑範圍時,路由之間發生名稱衝突。例如:

scope "admin" do
  resources :photos, as: "admin_photos"
end

resources :photos

這會將 /admin/photos 的路由輔助方法從 photos_pathnew_photos_path 等,變更為 admin_photos_pathnew_admin_photo_path 等。如果在 scoped 的 resources :photos 上沒有加上 as: 'admin_photos',則未 scoped 的 resources :photos 將不會有任何路由輔助方法。

要為一組路由輔助方法加上前綴,可以將 :asscope 搭配使用:

scope "admin", as: "admin" do
  resources :photos, :accounts
end

resources :photos, :accounts

如同之前,這會將 /admin scope 的資源輔助方法變更為 admin_photos_pathadmin_accounts_path,並允許未 scoped 的資源使用 photos_pathaccounts_path

namespace scope 會自動加上 :as,以及 :module:path 前綴。

4.6 在巢狀資源中使用 :as

:as 選項也可以覆寫巢狀路由中資源的路由輔助方法名稱。例如:

resources :magazines do
  resources :ads, as: "periodical_ads"
end

這會建立像 magazine_periodical_ads_urledit_magazine_periodical_ad_path 這樣的路由輔助方法,而不是預設的 magazine_ads_urledit_magazine_ad_path

4.7 參數化範圍

你可以為路由加上具名參數前綴:

scope ":account_id", as: "account", constraints: { account_id: /\d+/ } do
  resources :articles
end

這會提供像 /1/articles/9 這樣的路徑,並允許你在控制器、輔助方法和視圖中,以 params[:account_id] 的形式引用路徑的 account_id 部分。

它也會產生以 account_ 為前綴的路徑和 URL 輔助方法,你可以像預期一樣傳遞物件給它們。

account_article_path(@account, @article) # => /1/article/9
url_for([@account, @article])            # => /1/article/9
form_with(model: [@account, @article])   # => <form action="/1/article/9" ...>

:as 選項也不是強制性的,但如果沒有它,Rails 在評估 url_for([@account, @article]) 或其他依賴 url_for 的輔助方法(例如 form_with)時,會引發錯誤。

4.8 限制建立的路由

預設情況下,使用 resources 會為七個預設動作(indexshownewcreateeditupdatedestroy)建立路由。你可以使用 :only:except 選項來限制建立哪些路由。

:only 選項會告訴 Rails 只建立指定的路由:

resources :photos, only: [:index, :show]

現在,對 /photos/photos/:idGET 請求會成功,但對 /photosPOST 請求將無法匹配。

:except 選項指定 Rails 應建立的路由或路由清單:

resources :photos, except: :destroy

在這種情況下,Rails 會建立所有正常的路由,除了 destroy 的路由(對 /photos/:idDELETE 請求)。

如果你的應用程式有很多 RESTful 路由,使用 :only:except 只產生你實際需要的路由,可以減少記憶體使用量,並透過消除未使用的路由來加快路由處理速度。

4.9 翻譯路徑

使用 scope,我們可以更改 resources 產生的路徑名稱:

scope(path_names: { new: "neu", edit: "bearbeiten" }) do
  resources :categories, path: "kategorien"
end

Rails 現在會建立到 CategoriesController 的路由。

HTTP 動詞 路徑 Controller#Action (控制器#動作) 命名路由輔助方法
GET /kategorien categories#index categories_path
GET /kategorien/neu categories#new new_category_path
POST /kategorien categories#create categories_path
GET /kategorien/:id categories#show category_path(:id)
GET /kategorien/:id/bearbeiten categories#edit edit_category_path(:id)
PATCH/PUT /kategorien/:id categories#update category_path(:id)
DELETE /kategorien/:id categories#destroy category_path(:id)

4.10 指定資源的單數形式

如果你需要覆寫資源的單數形式,你可以透過 inflections 向 Active Support Inflector 添加規則:

ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular "tooth", "teeth"
end

4.11 重新命名預設的路由參數 id

可以使用 :param 選項重新命名預設的參數名稱 id。例如:

resources :videos, param: :identifier

現在將使用 params[:identifier] 而不是 params[:id]

    videos GET  /videos(.:format)                  videos#index
           POST /videos(.:format)                  videos#create
 new_video GET  /videos/new(.:format)              videos#new
edit_video GET  /videos/:identifier/edit(.:format) videos#edit
Video.find_by(id: params[:identifier])

# Instead of
Video.find_by(id: params[:id])

你可以覆寫關聯模型的 ActiveRecord::Base#to_param 來建構 URL:

class Video < ApplicationRecord
  def to_param
    identifier
  end
end
irb> video = Video.find_by(identifier: "Roman-Holiday")
irb> edit_video_path(video)
=> "/videos/Roman-Holiday/edit"

5 檢查路由

Rails 提供幾種不同的方式來檢查和測試你的路由。

5.1 列出現有路由

若要取得應用程式中可用路由的完整清單,請在 開發 環境中造訪 https://127.0.0.1:3000/rails/info/routes。你也可以在終端機中執行 bin/rails routes 命令,以取得相同的輸出。

兩種方法都會列出你所有的路由,順序與它們在 config/routes.rb 中出現的順序相同。對於每個路由,你會看到:

  • 路由名稱(如果有的話)
  • 使用的 HTTP 動詞(如果路由不回應所有動詞)
  • 要匹配的 URL 模式
  • 路由的路由參數

例如,以下是 RESTful 路由的 bin/rails routes 輸出的一小部分:

    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
 new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit

路由名稱(例如上面的 new_user)可以被視為衍生路由輔助方法的基礎。若要取得路由輔助方法的名稱,請在路由名稱後加上後綴 _path_url(例如 new_user_path)。

你也可以使用 --expanded 選項來開啟擴展表格格式模式。

$ bin/rails routes --expanded

--[ Route 1 ]----------------------------------------------------
Prefix            | users
Verb              | GET
URI               | /users(.:format)
Controller#Action | users#index
--[ Route 2 ]----------------------------------------------------
Prefix            |
Verb              | POST
URI               | /users(.:format)
Controller#Action | users#create
--[ Route 3 ]----------------------------------------------------
Prefix            | new_user
Verb              | GET
URI               | /users/new(.:format)
Controller#Action | users#new
--[ Route 4 ]----------------------------------------------------
Prefix            | edit_user
Verb              | GET
URI               | /users/:id/edit(.:format)
Controller#Action | users#edit

5.2 搜尋路由

你可以使用 grep 選項:-g 來搜尋你的路由。這會輸出任何部分匹配 URL 輔助方法名稱、HTTP 動詞或 URL 路徑的路由。

$ bin/rails routes -g new_comment
$ bin/rails routes -g POST
$ bin/rails routes -g admin

如果你只想查看對應到特定控制器的路由,可以使用控制器選項:-c

$ bin/rails routes -c users
$ bin/rails routes -c admin/users
$ bin/rails routes -c Comments
$ bin/rails routes -c Articles::CommentsController

如果你將終端機視窗加寬,直到輸出行的文字沒有換行,或使用 --expanded 選項,bin/rails routes 的輸出會更容易閱讀。

5.3 列出未使用的路由

你可以使用 --unused 選項掃描應用程式中未使用的路由。Rails 中的「未使用」路由是指在 config/routes.rb 檔案中定義,但應用程式中的任何控制器動作或視圖都沒有引用的路由。例如:

$ bin/rails routes --unused
Found 8 unused routes:

     Prefix Verb   URI Pattern                Controller#Action
     people GET    /people(.:format)          people#index
            POST   /people(.:format)          people#create
 new_person GET    /people/new(.:format)      people#new
edit_person GET    /people/:id/edit(.:format) people#edit
     person GET    /people/:id(.:format)      people#show
            PATCH  /people/:id(.:format)      people#update
            PUT    /people/:id(.:format)      people#update
            DELETE /people/:id(.:format)      people#destroy

5.4 在 Rails Console 中的路由

你可以在 Rails Console 中使用 Rails.application.routes.url_helpers 來存取路由輔助方法。它們也可以透過 app 物件取得。例如:

irb> Rails.application.routes.url_helpers.users_path
=> "/users"

irb> user = User.first
=> #<User:0x00007fc1eab81628
irb> app.edit_user_path(user)
=> "/users/1/edit"

6 測試路由

Rails 提供三個內建斷言,旨在簡化路由測試:

6.1 assert_generates 斷言

assert_generates 斷言一組特定的選項會產生特定的路徑,並且可以與預設路由或自訂路由一起使用。例如:

assert_generates "/photos/1", { controller: "photos", action: "show", id: "1" }
assert_generates "/about", controller: "pages", action: "about"

6.2 assert_recognizes 斷言

assert_recognizesassert_generates 的反向。它斷言給定的路徑被識別,並將其路由到應用程式中的特定位置。例如:

assert_recognizes({ controller: "photos", action: "show", id: "1" }, "/photos/1")

你可以提供 :method 參數來指定 HTTP 動詞:

assert_recognizes({ controller: "photos", action: "create" }, { path: "photos", method: :post })

6.3 assert_routing 斷言

assert_routing 斷言會雙向檢查路由。它結合了 assert_generatesassert_recognizes 的功能。它會測試路徑是否產生選項,以及選項是否產生路徑:

assert_routing({ path: "photos", method: :post }, { controller: "photos", action: "create" })

7 使用 draw 分割大型路由檔案

在具有數千個路由的大型應用程式中,單個 config/routes.rb 檔案可能會變得笨重且難以閱讀。Rails 提供了一種方法,可以使用 draw 巨集將單個 routes.rb 檔案分成多個小檔案。

例如,你可以添加一個 admin.rb 檔案,其中包含與管理區域相關的所有路由,另一個 api.rb 檔案用於與 API 相關的資源等等。

# config/routes.rb

Rails.application.routes.draw do
  get "foo", to: "foo#bar"

  draw(:admin) # Will load another route file located in `config/routes/admin.rb`
end
# config/routes/admin.rb

namespace :admin do
  resources :comments
end

Rails.application.routes.draw 區塊內呼叫 draw(:admin) 本身會嘗試載入與給定參數同名的路由檔案(在此範例中為 admin.rb)。該檔案需要位於 config/routes 目錄或任何子目錄中(即 config/routes/admin.rbconfig/routes/external/admin.rb)。

你可以在次要路由檔案(例如 admin.rb)中使用一般的路由 DSL,但不要Rails.application.routes.draw 區塊包圍它。該區塊只能在主要的 config/routes.rb 檔案中使用。

除非你真的需要它,否則不要使用此功能。擁有多個路由檔案會使人在一個地方難以發現路由。對於大多數應用程式(即使是那些只有數百個路由的應用程式),開發人員更容易使用單個路由檔案。Rails 路由 DSL 已經提供了一種使用 namespacescope 以有組織的方式拆分路由的方法。



回到頂端