理解路由的目的
看懂routes.rb文件中的代碼
使用經典的hash風格或者現在比較流行的Restful風格構造你自己的路徑
斷定一個路徑會映射到哪一個controller和action
路由的雙重作用
Rails的路由是一個雙重的機制 - 你既能把樹木變成紙張,也能把紙張變成樹木.更准確的說,它既能將進入服務器的HTTP請求連接到你的controller,也能幫助你(在View內)生成URL而不需要使用硬編碼的字符串.
從URL到代碼當你的Rails應用接收到HTTP請求后,比如:
GET /patients/17
Rails的路由引擎就是把請求分發到你的應用中合適點的那些代碼.具體到這個例子,應用程序比較可能會運行patients controller中的show action,並展示id是17的patient的詳細信息.
從代碼到URL路由也可以反過來作用.如果你的應用包含了以下代碼
@patient = Patient.find(17)
<%= link_to “Patient Record”, patient_path(@patient) %>
那么,路由引擎就會把這段代碼解釋成這樣的URL: http://example.com/patients/17.這樣使用路由,比起硬編碼URL,可以降低你的應用程序的脆弱程度(增加程序健壯性),並且可以增加代碼的可讀性,使你的程序更容易被理解.
Patient需要被聲明成為resource才可以使用這種形式的路徑轉換
快速瀏覽Routes.rbRails的路由有兩個組陳部分:作為Rails一部分的路由引擎,還有包含有你的應用程序真正路徑的config/routes.rb文件.講授可以把什么東西放到routes.rb里面去是本文的目的,不過在此之前我們先概覽一下.
處理文件從格式上講,routes.rb只不過是被傳遞給ActionController::Routing:routes.draw的一個大大的 block. 這個文件里也可以有注釋,不過大多數情況下,應該是移行移行的代碼,每一行代表你應用程序的一條路徑.路徑有五種主要類型:
RESTful路徑 命名路徑 嵌套路徑 常規路徑 默認路徑每一個類型的路徑都會在隨后詳細闡述. 當有請求進入時, routes.rb文件自頂向下出路.請求會被分發到第一個匹配的路徑.如果沒有匹配的路徑,Rails會返回給調用者一個HTTP 404.
RESTful路徑RESTful路徑沾了Rails內建REST機制的光,只用一句單獨的聲明就包含了很多路由信息.一個RESTful路徑看起來是這樣的:
map.resources :books
命名路徑命名路徑在處理請求的同時,也可以給你的代碼提供非常具有可讀性的鏈接.這是一個典型的命名路徑:
map.login ‘/login’, :controller => ’sessions’, :action => ‘new’
嵌套路徑嵌套路徑可以讓你在一個resource里面包含另一個resource.你待會兒就會知道它是怎么被轉化成URL(絕對路徑 http://niuwa.org/index.html)和path(相對路徑 /index.html)的.舉例來說,如果你的應用包含很多部分,每個部分屬於一個包(assembly),你也許可以這么寫:
map.resources :assemblies do |assemblies| assemblies.resources :parts end
常規路徑在很多應用中,你會看到非RESTful的路由,它們顯式的鏈接URL和action.例如:
map.connect ‘parts/:number’, :controller => ‘inventory’, :action => ’show’
默認路徑默認路徑十一個安全網,抓住那些沒有匹配上其他路徑的請求.很多Rails應用都會包含這兩條默認路徑:
map.connect ‘:controller/:action/:id’ map.connect ‘:controller/:action/:id.:format’
這兩個默認路徑是你創建Rails應用的時候自動生成的.你可以為你的應用里面的所有東西使用RESTful的路徑,那你就有可能想去掉這兩條默認路徑.在你去掉它們之前請確保你沒有用到它們.
RESTful路由是目前Rails的標准路由方式,並且它也是你在新建的應用中首先使用的方式.要理解RESTful路有可能要花上一點時間,不 過這樣 的努力是值得的;你的代碼會變得更容易閱讀,並且當你使用這種路由方式的時候,你會跟Rails配合的很好,而不是跟Rails對着干.
什么是REST?RESTful 路由的基礎是由Roy Fielding的博士論文提出的,參見: Architectural Styles and the Design of Network-based Software Architectures. 幸運的是,你不需要看懂整篇博士論文就可以理解Rails中的REST是怎么回事.REST是Representational State Transfer(基於表現的狀態轉移)的縮寫.對我們來說,主要有兩點:
使用資源定位符(對我們來說就是URL)來表示資源 在系統的不同組件之間轉移表現狀態舉例來說,對於Rails應用中這樣的一個請求:
DELETE /phote/17
會被理解成是操作ID是17的photo,並且指示出了期望的操作 - 刪除該資源.REST是web應用架構的一種自然的方式,並且Rails進一步使用約定(convention)隱藏了RESTful的某些復雜性使之更加自然(大概是指用起來更簡單).
CRUD,動詞和action在RAils中,一個RESTful路徑提供了HTTP動詞(也就是GET, PUT等等),controller actions和(隱含的)CRUD數據庫操作之間的的映射.路由文件中一個單獨的入口如下所示:
map.resources :photos
在你的應用中創建了七個不同的路徑:
GET | /photos | Photos | index | display a list of all photos |
GET | /photos/new | Photos | new | return anHTMLform for creating a new photo |
POST | /photos | Photos | create | create a new photo |
GET | /photos/1 | Photos | show | display a specific photo |
GET | /photos/1/edit | Photos | edit | return anHTMLform for editing a photo |
PUT | /photos/1 | Photos | update | update a specific photo |
DELETE | /photos/1 | Photos | destroy | delete a specific photo |
對這些路徑(由之前的resource定義生成的),resource的id可以在相應的controller action中使用params[:id]得到.
如果你一直在你的應用程序里面使用RESTful路徑,你應該刪除routes.rb中的默認路徑,這樣就會迫使Rails使用HTTP動詞和路徑間的映射.
URL和Path創建RESTful路徑會在你的應用程序里面生成一堆helper:
photos_url 和photos_path映射到index和create兩個action new_photo_url和new_photo_path映射到new action edit_photo_url和edit_photo_path映射到edit action photo_url和photo_path映射到show, update和destroy三個action因為路由同時使用HTTP動詞和path二者分發請求,因此這七個RESTful路由生成的路徑只有4對helper.
在這里,以_url結尾的helper生成應用程序能理解的整個URL(包含主機名),而以_path結尾的helper僅生成從應用程序根目錄開始的path(不包含主機名).例如:
photos_url# => “http://www.example.com/photos”
photos_path# => “/photos”
如果你需要為多個資源創建路徑,你可以使用一次map.resources調用就定義它們:
map.resources :photos, :books, :videos
跟這樣定義的效果是一樣的:
map.resources :photos map.resources :books map.resources :videos
單數形式資源你也可以應用RESTful路由定義單數形式的資源.這是,你需要使用map.resource代替剛才的map.resources,這時生成的路徑會略有不同:
map.resource :geocoder
創建六個不同的路徑:
GET | /geocoder/new | Geocoders | new | return anHTMLform for creating the new geocoder |
POST | /geocoder | Geocoders | create | create the new geocoder |
GET | /geocoder | Geocoders | show | display the one and only geocoder resource |
GET | /geocoder/edit | Geocoders | edit | return anHTMLform for editing the geocoder |
PUT | /geocoder | Geocoders | update | update the one and only geocoder resource |
DELETE | /geocoder | Geocoders | destroy | delete the geocoder resource |
雖然routes.rb中的資源名稱是單數,但是對應的controller名稱依然是復數.
一個單數形式的RESTful路徑生成如下的helper:
new_geocoder_url 和new_geocoder_path映射到new action edit_geocoder_url和edit_geocoder_path映射到edit action geocoder_url和geocode_path映射到create, update和destroy三個action 自定義資源雖然使用RESTful路由約定對很多應用來說基本就足夠了,不過還是有一些其他的方法自定義RESTful路徑的工作方式.這些選項包括:
:controller :singular :requirements :conditions :as :path_names :path_prefix :name_prefix :only :except你也可以使用:member和:collection選項添加路徑,這個在本文中稍后討論.
使用:controller:controller選項使你可以使用和公開的資源名稱不同的controller名稱,例如:
map.resources :photos, :controller => “images”
生成helper時會依據資源的名稱, 而不是controller的名稱.因此,在這個例子里,就會得到photos_path,new_photo_path等等.controller命名空間和路由
默認路由:
正則路由:
命名路由:
根路由:
路由簡寫技巧:
:to 鍵的省略:
注意:
:as 在rails3中是改變 helper, 在rails2中是改變 path
當路徑和控制器(及action)一至時,可省略指派控制器部分
Verb路由
當需要限制http請求方法的時候通過鍵 :via ,也可以直接把方法寫在最前面:
resources路由:
:shallow用法:
Rails3中的shallow用法與Rails2中一致
使用:shallow前后相同部分:
blog_comments | GET | /blogs/:blog_id/comments(.:format) | {:controller=>"comments", :action=>"index"} | |
blog_comments | POST | /blogs/:blog_id/comments(.:format) | {:controller=>"comments", :action=>"create"} | |
new_blog_comment | GET | /blogs/:blog_id/comments/new(.:format) | {:controller=>"comments", :action=>"new"} | |
blogs | GET | /blogs(.:format) | {:controller=>"blogs", :action=>"index"} | |
blogs | POST | /blogs(.:format) | {:controller=>"blogs", :action=>"create"} | |
new_blog | GET | /blogs/new(.:format) | {:controller=>"blogs", :action=>"new"} | |
edit_blog | GET | /blogs/:id/edit(.:format) | {:controller=>"blogs", :action=>"edit"} | |
blog | GET | /blogs/:id(.:format) | {:controller=>"blogs", :action=>"show"} | |
blog | PUT | /blogs/:id(.:format) | {:controller=>"blogs", :action=>"update"} | |
blog | DELETE | /blogs/:id(.:format) | {:controller=>"blogs", :action=>"destroy"} |
使用:shallow前后不同部分:
不使用shallow選項:
edit_blog_comment | GET | /blogs/:blog_id/comments/:id/edit(.:format) | {:controller=>"comments", :action=>"edit"} |
blog_comment | GET | /blogs/:blog_id/comments/:id(.:format) | {:controller=>"comments", :action=>"show"} |
blog_comment | PUT | /blogs/:blog_id/comments/:id(.:format) | {:controller=>"comments", :action=>"update"} |
blog_comment | DELETE | /blogs/:blog_id/comments/:id(.:format) | {:controller=>"comments", :action=>"destroy"} |
使用shallow選項后:
edit_comment | GET | /comments/:id/edit(.:format) | {:controller=>"comments", :action=>"edit"} |
comment | GET | /comments/:id(.:format) | {:controller=>"comments", :action=>"show"} |
comment | PUT | /comments/:id(.:format) | {:controller=>"comments", :action=>"update"} |
comment | DELETE | /comments/:id(.:format) | {:controller=>"comments", :action=>"destroy"} |
可以看出使用shallow選項后,對於已經存在的資源使用簡化方式操作,具體行為涉及到 edit\show\update\destroy 四種
另外,shallow選項的有效范圍是對自身及嵌套的資源都有效,如下面這個例子:
這個例子中 albums、photos、images 都會使用簡化方式,而 magazines 不會。特別注意:這種嵌套方式極不推薦,一般嵌套的層級最好不要超過一級
scope路由
:path 改變Path,:module 改變Controller, :name_prefix || :as 改變 helper
scope 'admin' do resources :posts end # 行當於: scope :path => 'admin' do resources :posts end
scope 'admin' do resources :posts end # 行當於: scope :path => 'admin' do resources :posts end
在路由中定義跳轉:
路由中的限制:
路由通配符:
Rack: