跳至內文 跳至搜尋

路由模組提供 Ruby 中的 URL 改寫。這是將傳入的請求重新導向至控制器和動作的一種方式。這麼一來便可取代 mod_rewrite 規則。最棒的是,Rails 的 Routing 可搭配任何網路伺服器使用。路由會定義在 config/routes.rb 中。

可以將建立路由想成是替請求繪製一張地圖。地圖會根據某些預先定義的模式告訴請求前往哪裡。

Rails.application.routes.draw do
  Pattern 1 tells some request to go to one place
  Pattern 2 tell them to go to another
  ...
end

下列符號為特殊符號

:controller maps to your controller name
:action     maps to an action with your controllers

其他名稱只會個別對應至參數,就像 :id

資源

資源路由可讓您快速宣告給定資源控制器的所有常見路由。資源路由會在一行 code 中宣告路由,而不是為 indexshowneweditcreateupdatedestroy 動作宣告個別的路由。

resources :photos

有時,您擁有某個資源,而使用者總是不參照 ID 即可查詢該資源。常見範例是 /profile 總是會顯示目前登入使用者的個人資料。此種情況下,您可以使用單數資源來將 /profile(而不是 /profile/:id)對應至顯示動作。

resource :profile

資源通常會是其他資源的邏輯子項。

resources :magazines do
  resources :ads
end

您可能希望將控制器群組整理在命名空間中。最常見的情況是,您可能會將多個管理控制器群組在 admin 命名空間中。您會將這些控制器放置在 app/controllers/admin 目錄中,而且可以將它們在路由器中群組在一起。

namespace "admin" do
  resources :posts, :comments
end

或者,您可以使用 scope 在不使用個別目錄的情況下,將前置詞新增至路徑。scope 會採用其他選項,而這些選項套用於所有內含路由。

scope path: "/cpanel", as: 'admin' do
  resources :posts, :comments
end

詳細資訊請參閱 Routing::Mapper::Resources#resourcesRouting::Mapper::Scoping#namespaceRouting::Mapper::Scoping#scope

非資源路由

對於與 resources 架構不符的路由,您可以使用 HTTP 輔助方法 getpostpatchputdelete

get 'post/:id', to: 'posts#show'
post 'post/:id', to: 'posts#create_comment'

現在,如果您對 /posts/:id 發出 POST 請求,系統將路由至 create_comment 動作。對同個 URL 發出 GET 請求將會路由至 show 動作。

如果您的路由需要回應多種 HTTP 方法(或所有方法),那麼在 match 上使用 :via 選項會比較好。

match 'post/:id', to: 'posts#show', via: [:get, :post]

命名路由

可以透過傳遞 :as 選項來命名路由,讓您可以在來源中輕鬆參照 name_of_route_url(完整 URL)和 name_of_route_path(URI 路徑)。

範例

# In config/routes.rb
get '/login', to: 'accounts#login', as: 'login'

# With render, redirect_to, tests, etc.
redirect_to login_url

也可以傳遞引數。

redirect_to show_item_path(id: 25)

使用 root 作為縮寫來為根路徑 “/” 命名路由。

# In config/routes.rb
root to: 'blogs#index'

# would recognize http://www.example.com/ as
params = { controller: 'blogs', action: 'index' }

# and provide these named routes
root_url   # => 'http://www.example.com/'
root_path  # => '/'

注意:在使用 controller 時,路由只會根據您呼叫區塊參數中的方法,而不是 map 來命名。

# In config/routes.rb
controller :blog do
  get 'blog/show'    => :list
  get 'blog/delete'  => :delete
  get 'blog/edit'    => :edit
end

# provides named routes for show, delete, and edit
link_to @article.title, blog_show_path(id: @article.id)

美化 URL

路由可以產生美化過的 URL。例如

get '/articles/:year/:month/:day', to: 'articles#find_by_id', constraints: {
  year:       /\d{4}/,
  month:      /\d{1,2}/,
  day:        /\d{1,2}/
}

使用上述路由,URL “localhost:3000/articles/2005/11/06” 會對應至

params = {year: '2005', month: '11', day: '06'}

正規表示法和參數

您可以指定正規表示式來定義參數的格式。

controller 'geocode' do
  get 'geocode/:postalcode', to: :show, constraints: {
    postalcode: /\d{5}(-\d{4})?/
  }
end

約束可以包含『忽略大小寫』和『延伸語法』正規表示式修改詞。

controller 'geocode' do
  get 'geocode/:postalcode', to: :show, constraints: {
    postalcode: /hx\d\d\s\d[a-z]{2}/i
  }
end

controller 'geocode' do
  get 'geocode/:postalcode', to: :show, constraints: {
    postalcode: /# Postalcode format
       \d{5} #Prefix
       (-\d{4})? #Suffix
       /x
  }
end

使用多行修改詞將產生ArgumentError。編碼正規表示式修改詞會被自動忽略。比對將始終使用預設編碼或 ASCII。

外部重新導向

您可以使用路由器中的重新導向輔助函數將任何路徑重新導向至另一條路徑。

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

Unicode 字元路由

您可以在路由器中指定 Unicode 字元路由。

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

Routing to Rack Applications

您不一定要指定 String(例如對應 PostsController 中索引動作的 posts#index),而是可以指定任何 Rack 應用程式做為比對器的端點。

get "/application.js", to: Sprockets

重新載入路由

如果您覺得有必要,您可以重新載入路由。

Rails.application.reload_routes!

如果檔案已自上次載入以來經過修改,這將清除所有已命名路由並重新載入 config/routes.rb。若要強制重新載入,請使用 reload!

測試路由

兩個用於測試路由的主要方法

assert_routing

def test_movie_route_properly_splits
  opts = {controller: "plugin", action: "checkout", id: "2"}
  assert_routing "plugin/checkout/2", opts
end

assert_routing 讓您可以測試路由是否正確解析成選項。

assert_recognizes

def test_route_has_options
  opts = {controller: "plugin", action: "show", id: "12"}
  assert_recognizes opts, "/plugins/show/12"
end

請注意兩者之間的細微差異:assert_routing 測試 URL 是否符合選項,而 assert_recognizes 測試 URL 是否正確解析成參數。

在測試中,您可以僅將 URL 或已命名路由傳遞給 getpost

def send_to_jail
  get '/jail'
  assert_response :success
end

def goes_to_login
  get login_url
  #...
end

檢視所有路由的清單

$ bin/rails routes

使用 -c 指定特定控制器,或使用 -g grep 路由。在與顯示路由垂直顯示的 --expanded 搭配使用時非常實用。

命名空間