美文网首页
Rails路由

Rails路由

作者: 忽如寄 | 来源:发表于2018-05-12 18:51 被阅读27次

    资源路由

    一行代码完成资源资源路由声明:

    resources :photos
    

    这会创建7个不同的路由,这些路由会映射到 Photos 控制器上。

    这样4个URL地址就会映射到7个不同的控制器动作上。

    用于生成路径和URL地址的辅助方法

    在创建资源路由时,会同时创建多个可以在控制器中使用的辅助方法,如上面的资源路由会创建以下方法:

    • photos_path:返回值为 /photos

    • new_photos_path:返回值为 /photos/new

    • edit_photo_path(:id):返回值为 /photos/:id/edit

    • photo_path(:id):返回值为 /photos/:id

    这些方法都有对应的_url形式(photos_url),前者返回的是路径,后者返回的是完整的url地址。

    同时定义多个资源

    可以同时定义多个资源路由:

    resources :photos, :books, :videos
    

    等价于:

    resources :photos
    resources :books
    resources :videos
    

    单数资源

    使用 resource 方法可以创建单数资源,这会创建6个不同的路由:

    有时候在复数资源中希望能够不使用ID就能查找资源,如显示当前登录用户的信息:

    get 'profile', to: 'users#show'
    

    如果 get 方法的to选项的值是字符串,那么这个字符串应该使用controller#action形式,如果是表示动作的符号,则还需要添加controller选项:

    get 'profile', to: :show, controller: 'users'
    

    控制命名空间和路由

    把控制器放入同一命名空间是非常常见的,如将管理员有关的控制器置于 Admin:: 命名空间中,这样可以把控制器文件放在 app/controllers/admin 文件夹中,在路由中这样声明:

    namespace :admin do
        resources :articles, :comments
    end
    

    对于articles资源


    如果想把 /articles 路径(不带/admin前缀)映射到Admin::Articles控制器上,可以这样声明:

    scope module: 'admin' do
        resources :articles, :comments
    end
    

    或者

    resources :articles, module: 'admin'
    resources :articles, module: 'admin'
    

    或者:

    resources :articles, path: '/admin/articles'
    

    嵌套资源

    有些资源是其他资源的子资源,这种情况非常常见:

    class Magazine < ApplicationRecord
        has_many :ads
    end
    
    class Ad < ApplicationRecord
        belongs_to :magazine
    end
    

    通过嵌套路由来反映模型关联:

    resources :magazine do
        resources :ads
    end
    

    对于嵌套路由,可以不断嵌套:

    resources :publishers do
        resources :magazine do
            resources :photos
        end
    end
    

    但是显然嵌套太深是非常麻烦的,经验告诉我们嵌套资源层级不应该超过一层,而避免嵌套过深的方法之一就是把动作集合放在父资源中,这样既可以表明层级关系,又不必嵌套成员动作:

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

    当然,使用 :shallow 选项可以简化上面的代码:

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

    当然,在复选项中使用 :shallow 选项,这样会在所有的子资源中使用 :shallow 选项:

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

    也可以使用 shallow 方法创建作用域,使得所有嵌套均为浅层嵌套:

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

    使用scope方法也可以来定义浅层路由,且有两个选项,:shallow_path 选项会为成员路径添加前缀:

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

    :shallow_prefix 选项会为具名方法添加指定前缀:

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

    路由concern

    路由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
    

    从对象创建路径和RUL地址

    除了使用路由辅助方法,Rails还可以从参数数组创建路径和URL地址,假如有以下路由:

    resources :magazine do
        resources :ads
    end
    

    使用 magazine_ad_path 方法时,可以传入Magazine和Ad的实例,而不只是数字ID:

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

    还可以使用 url_for 方法时传入一组对象,Rails会自动确定对应的路由:

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

    Rails能够识别各个实例,自动使用 magazine_ad_path 辅助方法。当然在使用 link_to 等辅助方法时,可以只指定对象,而不必完整调用 url_for 方法:

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

    如果想要链接到其他控制器动作,只需把动作名称作为第一个元素插入对象数组即可:

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

    这样就可把模型实例看做URL地址,这是使用资源式风格最关键的优势之一。

    非资源式路由

    和资源路由自动生成一系列路由不同,这时需要分别声明各个路由,非资源路由可以把任意URL地址映射到控制器动作的路由。

    绑定参数

    声明普通路由时,可以使用符号作为参数:

    get 'photos(/:id)', to: :display
    

    在处理 /photos/1 请求时,会把请求映射到 Photos 控制器的 display 动作上,并把参数1传入params[:id],并将路由映射到 PhotosController#display 上,并且 /photos 请求也会映射到这个控制器动作上,因为 :id 在括号中,是可选参数。

    动态片段

    声明普通路由时,允许使用多个动态片段,动态片段会传入params,以便在控制器动作中使用:

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

    /photos/1/2 请求会被映射到 photos#show 动作上,这时 params[:id] 的值是 1 ,params[:user_id] 的值是 2

    查询字符串

    params 也包含了查询字符串中的所有参数,如:

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

    /photos/1?user_id=2 请求也会映射到 Photos#show 控制器动作上,这时params的值是

    {controller: 'photos', action: 'show', id: '1', user_id: '2'}
    

    定义默认值

    :defaults 选项设定的散列为路由定义默认值,未通过动态片段定义的参数也可以指定默认值

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

    Rails会把 /photos/12 路径映射到 Photos#show 动作上,并把 params[:format] 设为 'jpg'

    当然 defaults 还有块的形式,可以为多个路由定义默认值:

    defaults format: :json do
        resources :photos
    end
    

    当然需要注意的是查询参数是不会覆盖默认值的

    为路由命名

    可以使用 :as 选项来为路由命名

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

    这个路由声明会创建 logout_path 和 logout_url 这两个具名辅助方法

    路由命名可以覆盖资源路由定义的路由辅助方法:

    get ':username', to: 'users#show', as: :user
    

    HTTP方法约束

    通过使用 match 方法和 :via 选项,可以一次匹配多个HTTP方法:

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

    通过 via: :all 选项,路由可以匹配所有的HTTP方法

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

    把GET和POST请求映射到同一个控制器动作上会带来安全隐患,通常我们应该避免将不同的HTTP方法映射到同一个控制器动作上。

    片段约束

    使用 :contraints 选项可以约束动态片段的格式:

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

    这个路由会匹配 /photos/A12345 路径,但不会匹配 /photos/893 路径,这个还可以简写为:

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

    :contraints 选项的值可以是正则表达式,但不能使用 ^ 符号,比如下面就是错误的:

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

    路由通配符和通配符片段

    路由通配符用于指定特殊参数,这个参数会匹配路由的所有剩余部分:

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

    这个路由会匹配 photos/12 和 /photos/long/path/to/12 路径,并把 params[:other] 分别设置为 "12" 和 "long/path/to/12"。像 *other 这样以星号开头的片段,称作“通配符片段”。

    通配符片段可以出现在路由中的任何位置:

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

    重定向

    在路由中可以使用 redirect 辅助方法进行重定向

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

    重定向中也可以使用源路径的动态片段:

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

    redirect 默认是301永久重定向,有些浏览器和代理服务器缓存这种类型的重定向,从而导致无法访问重定向前的网页,为了避免这种情况,我们可以使用 :status 选项修改响应状态:

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

    使用 root 方法

    root 方法指明如何处理根路径的请求:

    root to: 'pages#main'
    

    简易写法

    root 'pages#main'
    

    root路由只处理 GET 请求

    unicode 字符路由

    声明路由时,可以直接使用 Unicode 字符:

    get "忽如寄" , to: 'welcome#index'
    

    自定义资源路由

    指定控制器

    :controller 选项用于显式指定资源使用的控制器:

    resources :photos, controller: 'images'
    

    这时路由会把 /photos 路径映射到 Images 控制器上

    对于命名空间中的控制器,可以使用目录表示法:

    resources :user_permissions, controller: 'admin/user_permissions'
    

    指定约束

    :constraints 选项用于指定隐式 ID 必须满足格式要求

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

    这时会约束 :id 参数,路由不会匹配 /photos/1 路径,会匹配 /photos/PR12

    当然也可以同时约束多个路由:

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

    覆盖具名路由辅助方法

    resources :photos, as: 'images'
    

    此时的具名辅助方法被修改为:


    覆盖 new 和 edit 片段

    :path_names 选项用于覆盖路径中自动生成的 new 和 edit 片段

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

    这个路由能够识别以下路径:

    /photos/make
    
    /photos/1/change
    

    :path_names 选项不会改变控制器动作的名称,仍然映射到 new 和 edit 动作上

    限制创建的路由

    Rails 默认会为每个 REST 式路由创建7个默认动作,可以使用 :only:except 选项来微调此行为。 :only 选项用于指定想生成的路由:

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

    :except 选项用于指定不想生成的路由:

    resources :photos, except: :destroy
    

    本地化路径

    使用 scope 方法,可以修改 resources 方法生成的路径名称:

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

    嵌套资源使用 :as 选项

    这会覆盖自动生成的辅助方法名称:

    resources :magazine do
        resources :ads, as: 'periodical_ads'
    end
    

    这会生成 magazine_periodical_ads_url 等辅助方法。

    相关文章

      网友评论

          本文标题:Rails路由

          本文链接:https://www.haomeiwen.com/subject/gcuhdftx.html