RESTful 路由


RESTful 與 Rails 中介紹過Rails對REST的基本支援,除了基本的resources設定之外,你還可以作一些進階設定,例如單個資源的URL定義,像是想對messages/:id/preview這樣的路由作定義,可以如下:

resources :messages do
    member do
        get 'preview'
    end
end

如此一來,就可以使用對像messages/1/preview作GET請求,請求會由messages_controller.rb中定義的preview動作處理,有preview_message_path與preview_message_url輔助方法可以使用。member中也可以使用match設定。例如:

resources :messages do
    member do
        match 'preview', :to => 'messages#preview', :via => 'post'
    end
end

也可以如下定義:

resources :messages do
    get 'preview', :on => :member
end

也可以使用rake routes來得知路由對應:

~gossip\$ rake routes
preview_message GET    /messages/:id/preview(.:format) {:action=>"preview", :controller=>"messages"}
       messages GET    /messages(.:format)             {:action=>"index", :controller=>"messages"}
                POST   /messages(.:format)             {:action=>"create", :controller=>"messages"}
    new_message GET    /messages/new(.:format)         {:action=>"new", :controller=>"messages"}
   edit_message GET    /messages/:id/edit(.:format)    {:action=>"edit", :controller=>"messages"}
        message GET    /messages/:id(.:format)         {:action=>"show", :controller=>"messages"}
                PUT    /messages/:id(.:format)         {:action=>"update", :controller=>"messages"}
                DELETE /messages/:id(.:format)         {:action=>"destroy", :controller=>"messages"}

如果想對多個資源的URL作定義,例如想對messages/search的GET作定義,則可以如下:

resources :messages do
    collection do
        get 'search'
    end
end

如此也會產生search_messages_path與search_messages_url可以使用。可以使用rake routes來得知路由對應:

~gossip\$ rake routes
search_messages GET    /messages/search(.:format)   {:action=>"search", :controller=>"messages"}
       messages GET    /messages(.:format)          {:action=>"index", :controller=>"messages"}
                POST   /messages(.:format)          {:action=>"create", :controller=>"messages"}
    new_message GET    /messages/new(.:format)      {:action=>"new", :controller=>"messages"}
   edit_message GET    /messages/:id/edit(.:format) {:action=>"edit", :controller=>"messages"}
        message GET    /messages/:id(.:format)      {:action=>"show", :controller=>"messages"}
                PUT    /messages/:id(.:format)      {:action=>"update", :controller=>"messages"}
                DELETE /messages/:id(.:format)      {:action=>"destroy", :controller=>"messages"}

資源有時必須巢狀顯示,例如messages/1的回應,也許可以用messages/1/replies來表示(訊息與回應為 一對多 的情況),這時可以如下設定:

resources :messages do
    resources :replies
end

使用rake routes來得知路由對應:

~gossip\$ rake routes
   message_replies GET    /messages/:message_id/replies(.:format)          {:action=>"index", :controller=>"replies"}
                   POST   /messages/:message_id/replies(.:format)          {:action=>"create", :controller=>"replies"}
 new_message_reply GET    /messages/:message_id/replies/new(.:format)      {:action=>"new", :controller=>"replies"}
edit_message_reply GET    /messages/:message_id/replies/:id/edit(.:format) {:action=>"edit", :controller=>"replies"}
     message_reply GET    /messages/:message_id/replies/:id(.:format)      {:action=>"show", :controller=>"replies"}
                   PUT    /messages/:message_id/replies/:id(.:format)      {:action=>"update", :controller=>"replies"}
                   DELETE /messages/:message_id/replies/:id(.:format)      {:action=>"destroy", :controller=>"replies"}
          messages GET    /messages(.:format)                              {:action=>"index", :controller=>"messages"}
                   POST   /messages(.:format)                              {:action=>"create", :controller=>"messages"}
       new_message GET    /messages/new(.:format)                          {:action=>"new", :controller=>"messages"}
      edit_message GET    /messages/:id/edit(.:format)                     {:action=>"edit", :controller=>"messages"}
           message GET    /messages/:id(.:format)                          {:action=>"show", :controller=>"messages"}
                   PUT    /messages/:id(.:format)                          {:action=>"update", :controller=>"messages"}
                   DELETE /messages/:id(.:format)                          {:action=>"destroy", :controller=>"messages"}

也就是說實際上處理的動作,必須在replies_controller.rb中定義RepliesController,並於其中定義對應的動作,像先前member與collection定義時,若有不瞭解URL對應與輔助方法時,也可以使用rake routes來得知。

resources用來定義複數資源,如果要定義單數資源,可以使用resource(沒有s),例如若訊息與最佳解答可以如下定義(為 一對一 的情況):

resources :messages do
    resource :answer    # 單數
end

使用rake routes來得知路由對應:

~gossip\$ rake routes
     message_answer POST   /messages/:message_id/answer(.:format)      {:action=>"create", :controller=>"answers"}
 new_message_answer GET    /messages/:message_id/answer/new(.:format)  {:action=>"new", :controller=>"answers"}
edit_message_answer GET    /messages/:message_id/answer/edit(.:format) {:action=>"edit", :controller=>"answers"}
                    GET    /messages/:message_id/answer(.:format)      {:action=>"show", :controller=>"answers"}
                    PUT    /messages/:message_id/answer(.:format)      {:action=>"update", :controller=>"answers"}
                    DELETE /messages/:message_id/answer(.:format)      {:action=>"destroy", :controller=>"answers"}
           messages GET    /messages(.:format)                         {:action=>"index", :controller=>"messages"}
                    POST   /messages(.:format)                         {:action=>"create", :controller=>"messages"}
        new_message GET    /messages/new(.:format)                     {:action=>"new", :controller=>"messages"}
       edit_message GET    /messages/:id/edit(.:format)                {:action=>"edit", :controller=>"messages"}
            message GET    /messages/:id(.:format)                     {:action=>"show", :controller=>"messages"}
                    PUT    /messages/:id(.:format)                     {:action=>"update", :controller=>"messages"}
                    DELETE /messages/:id(.:format)                     {:action=>"destroy", :controller=>"messages"}

你可以為URL加上名稱空間。例如admin/messages/1、admin/messages/new這樣的URL,可以如下設定:

namespace :admin do
    resources :messages
end

使用rake routes來看有哪些路由對應:

~gossip\$ rake routes
    admin_messages GET    /admin/messages(.:format)          {:action=>"index", :controller=>"admin/messages"}
                   POST   /admin/messages(.:format)          {:action=>"create", :controller=>"admin/messages"}
 new_admin_message GET    /admin/messages/new(.:format)      {:action=>"new", :controller=>"admin/messages"}
edit_admin_message GET    /admin/messages/:id/edit(.:format) {:action=>"edit", :controller=>"admin/messages"}
     admin_message GET    /admin/messages/:id(.:format)      {:action=>"show", :controller=>"admin/messages"}
                   PUT    /admin/messages/:id(.:format)      {:action=>"update", :controller=>"admin/messages"}
                   DELETE /admin/messages/:id(.:format)      {:action=>"destroy", :controller=>"admin/messages"}

更多有關路由設定的內容,可以參考 Rails Routing from the Outside in,表單設計的範例可以參考 RESTful 與表單設計What's New in Edge Rails: Nested Object Forms