跳至内容 跳至搜索

路由模块提供原生 Ruby 中的 URL 重写。这是一种将传入请求重定向到控制器和操作的方法。它取代了 mod_rewrite 规则。最重要的是,Rails 的 Routing 可与任何 Web 服务器配合使用。路由在 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

资源

资源路由允许您快速声明给定资源控制器的所有常用路由。与其分别声明 indexshowneweditcreateupdatedestroy 操作的路由,资源路由在一行代码中声明了它们。

resources :photos

有时,您有一个资源,客户端总是会查找它,而无需引用 ID。一个常见的例子是,/profile 始终显示当前登录用户的个人资料。在这种情况下,您可以使用单数资源将 /profile(而不是 /profile/:id)映射到 show 操作。

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 时,路由只是根据您在块参数上调用的方法命名,而不是映射。

# 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

约束可以包含“ignorecase”和“extended syntax”正则表达式修饰符。

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。

外部重定向

您可以使用路由器中的 redirect 助手将任何路径重定向到另一个路径。

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

Unicode 字符路由

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

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

Routing 到 Rack 应用程序

您可以指定任何 Rack 应用程序作为匹配器的端点,而不是像 posts#index 这样的 String,它对应于 PostsController 中的 index 操作。

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 查找路由。与 --expanded 结合使用很有用,--expanded 会垂直显示路由。

命名空间