config/routes.rb中的設定,決定了請求會由哪個控制器的動作處理,這邊要先來介紹Rails中典型路由(Regular route)與命令路由(Named route)設定的方式(注意,routes.rb中越前頭的設定會先套用)。
你可以設定整個應用程式的首頁,例如若想要在連結http://localhost:3000時,等同於連結http://localhost:3000/messages/index,可以如下:
root :to => 'messages#index'
Rails應用程式預設首頁是public/index.html,必須將之移除,才會讓以上設定有效,當然,記得在messages_controller.rb中建立index方法,並在app/views/messages中建立index.html.erb作為首頁回應。
如果要將某個網址請求分配至某個控制器的動作,可以使用match。例如:
match 'messages/show', :to => 'messages#show', :via => 'get'
match 'messages/update', :to => 'message#update', :via => [:get, :post]
以上可以簡化為以下:
match 'messages/show' => 'messages#show', :via => 'get'
match 'messages/update' => 'message#update', :via => [:get, :post]
以上設定,相當於:
get 'messages/show' => 'messages#show'
get 'messages/update' => 'messages#update'
post 'messages/update' => 'messages#update'
match有些設定省略時會有預設,例如:
match 'messages/show'
相當於:
match 'messages/show' => 'messages#show'
例如:
get 'messages/show'
相當於:
match 'messages/show' => 'messages#show', :via => 'get'
在 MVC 與 Rails 中,messages_controller.rb中的show若要取得id請求參數,必須使用messages/show/?id=1的請求方式,如果想在請求messages/show/1時,將id設為1,可以如下:
match 'messages/show/:id' => 'messages#show'
實際上,Rails會試著將請求網址匹配至每個:name,不過有些:name有意義,例如:controller與:action,來想想,應用程式中會有許多網址代表不同的請求動作,例如messages/create代表建立新訊息,messages/show/1代表顯示第一筆訊息、messages/update/1代表更新第一筆訊息,messages/destroy/1代表刪除第一筆訊息等,如果要逐一設定,會像是以下:
match 'messages/create'
match 'messages/show/:id' => 'messages#show'
match 'messages/update/:id' => 'messages#update'
match 'messages/destroy/:id' => 'messages#destroy'
也可以直接使用:controller、:action來指定控制器與動作:
match 'messages/:id' => :controller => 'messages', :action => show
如上設定之後,請求messages/1就會轉發給mesages_controller.rb中的show方法處理。
隨著應用程式越來越大,請求網址的匹配設定會越來越多,實在很麻煩,針對以上的設定,此時可以僅設定如下一行:
match ':controller(/:action(/:id(.:format)))'
其中括號表示網址請求中可有可無,事實上,這行正是在routes.rb中最後一行註解的內容,例如若請求messages/destroy/1,則:controller會是messages,:action會是destroy,:id會是1,而Rails會根據:controller與:action,自動將請求分配至messages#destroy,藉此簡化設定,不過要注意,這會讓所有控制器的每個公開動作,都可以使用GET請求,如果不想被請求的動作,請在方法上加上private限定。
現在假設你的routes.rb中有以下內容:
root :to => 'messages#index'
match ':controller(/:action(/:id(.:format)))'
假設你想在show.html.erb中加上個回首頁的鏈結,則可以如下:
- show.html.erb
<ul>
<li><%= @message.name %>'s message</li>
<li><%= @message.content %></li>
</ul>
<%= link_to "Home", root_path %>
link_to是個輔助方法(Helper),會產生超鏈結語法,第一個參數是顯示的文件,第二個參數是實際的網址,在這邊使用root_path輔助方法來產生頁面的相對網址,如果使用root_url則會產生絕對網址。
實際上,有些match設定,都會產生*_path與*_url的命名路由輔助方法,例如:
match 'messages/show'
預設的命名路由就是messages_show、輔助方法就是messages_show_path、messages_show_url。你也可以自行取名,例如:
match 'messages' => 'messages#index', :as => 'index'
則命名路由為index,而輔助方法為index_path與index_url,你可以如下使用:
<%= link_to "Home", index_path %>
如果是以下:
match 'messages/:id' => :controller => 'messages', :action => show, :as => messages
則可以如下使用輔助方法,其中message參考至Message實例:
<%= link_to "Show", messages_path(message) %>
如果不使用命名路由的輔助方法,則可以在指定控制器與動作。例如:
<%= link_to "Home", :controller => 'messages', :action => 'index' %>
routes.rb中設定越前頭越先套用,*_url、*_path輔助方法、網址與控制器動作的對應,可以執行rake routes指令來得知。
如果想限制參數,可以如下:
match "/messages/show/:id" => "messages#show", :constraints => {:id => /\d/}
這會限制id一定要是一個整數,也可以使用contraints方法作進階限定,例如限定IP位址:
constraints(:ip => /(^127.0.0.1\$)|(^192.168.[0-9]{1,3}.[0-9]{1,3}\$)/) do
match "/admins/edit/:id" => "admins#edit"
end
Rails還支援RESTful路由設定,這在之後還會說明。