今回はルートの操作のメモです。リクエストのルーティングがうまく通っているか確認したり、ルーティングを作成する方法を復習します。
サンプルコードを作ります。フィードを一覧、登録、編集するFeedsControllerを作ります。
rails -d mysql sample_routes ruby script/generate scaffold feeds
config/routes.rbで以下のルート定義が既に行われているものとします。
#関係あるのはこっちだけ map.resources :feeds map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'
scaffoldしたのでroutes.rbには既に自動で2行目のRestfulなマッピングが定義されているはずです。4、5行目はrailsコマンドでプロジェクトを作成したときに既に作成されているものです。
まずはscript/consoleを使ってRoutesオブジェクトを取得します。
$ ruby script/consoleLoading development environment (Rails 2.3.5) >> rs = ActionController::Routing::Routes
定義されたルートの確認
>>puts rs.routes GET /feeds(.:format)? {:controller=>"feeds", :action=>"index"} POST /feeds(.:format)? {:controller=>"feeds", :action=>"create"} GET /feeds/new(.:format)? {:controller=>"feeds", :action=>"new"} GET /feeds/:id/edit(.:format)? {:controller=>"feeds", :action=>"edit"} GET /feeds/:id(.:format)? {:controller=>"feeds", :action=>"show"} PUT /feeds/:id(.:format)? {:controller=>"feeds", :action=>"update"} DELETE /feeds/:id(.:format)? {:controller=>"feeds", :action=>"destroy"}::
出力される項目は左からHTTP Method、ルート定義、割り当てられるコントローラ/アクション。
またはrake taskからでもルート定義を表示できます
$rake routes #grepが使える $rake routes|grep feeds
URLから割り当てられるコントローラ、アクションを見つける
>> rs.recognize_path "/feeds"=> {:controller=>"feeds", :action=>"index"}
混乱を避けるためmethodは指定しておいた方が良いです。
>> rs.recognize_path '/feeds/1' => {:controller=>"feeds", :action=>"1"} >> rs.recognize_path '/feeds/1', :method=>:get => {:controller=>"feeds", :action=>"show", :id=>"1"}
また、そもそもコントローラが実装されていない場合はルートはマッチしません
>> rs.recognize_path '/foo' ActionController::RoutingError: No route matches "/foo" with {} from /opt/ruby-enterprise-1.8.7/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/routing/recognition_optimisation.rb:66:in `recognize_path' from (irb):24
コントローラ、アクションからURLを逆引きする
#コントローラだけ指定すると期待した動作をする。 >> rs.generate :controller => :feeds => "/feeds"#idを指定すると定義されていないURLが帰ってくる >> rs.generate :controller => :feeds, :id => '123' => "/feeds?id=123"#recognize_pathでマッチしないルートなのでまあ無視しておこう。。。 >> rs.recognize_path '/feeds?id=123' ActionController::RoutingError: No route matches "/feeds?id=123" with {} from /opt/ruby-enterprise-1.8.7/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/routing/recognition_optimisation.rb:66:in `recognize_path' from (irb):20
作成前のコントローラのルートを作成する
#use_controllers! [”name_of_controller”] >> ActionController::Routing.use_controllers! ['entries'] => ["entries"] #ルート定義をリロードしないとコントローラが有効にならない >> load 'config/routes.rb'=> [] #確認 >> rs.recognize_path '/entries/show/1' => {:controller=>"entries", :action=>"show", :id=>"1"} #routes.rbのmapの設定を行っていないのでこうなる。 >> rs.recognize_path '/entries/1'=> {:controller=>"entries", :action=>"1"}
http://api.rubyonrails.org/classes/ActionController/Routing/RouteSet/Mapper.html
ActionController::Routing::Routes.drawのブロック中の操作
準備
>> rs = ActionController::Routing::Routes >> map = ActionController::Routing::RouteSet::Mapper.new rs
map.root
>> map.root :controller => "welcom", :action => "index" => ANY / {:controller=>"welcome", :action=>"index"}
map.connect
>> map.connect ':controller/ajax/:action' => ANY /:controller/ajax/:action/ {}
map.resources
>> map.resources :feeds => GET /feeds(.:format)? {:controller=>"feeds", :action=>"index"} POST /feeds(.:format)? {:controller=>"feeds", :action=>"create"} GET /feeds/new(.:format)? {:controller=>"feeds", :action=>"new"} GET /feeds/:id/edit(.:format)? {:controller=>"feeds", :action=>"edit"} GET /feeds/:id(.:format)? {:controller=>"feeds", :action=>"show"} PUT /feeds/:id(.:format)? {:controller=>"feeds", :action=>"update"} DELETE /feeds/:id(.:format)? {:controller=>"feeds", :action=>"destroy"}
map.resource
>> map.resource :daily_sum => GET /daily_sum/new(.:format)? {:controller=>"daily_sums", :action=>"new"} GET /daily_sum/edit(.:format)? {:controller=>"daily_sums", :action=>"edit"} GET /daily_sum(.:format)? {:controller=>"daily_sums", :action=>"show"} PUT /daily_sum(.:format)? {:controller=>"daily_sums", :action=>"update"} DELETE /daily_sum(.:format)? {:controller=>"daily_sums", :action=>"destroy"} POST /daily_sum(.:format)? {:controller=>"daily_sums", :action=>"create"}
map.resourcesと比較した違い
- indexがない
- リソースが単一なので:idをURLに使用しない
resourceのオプション
- :member, :collection
map.resources :japan :member => {:county => :get}, :collection => {:progress_population => :get}
member => /nihon/:id/history, collection => /nihon/log
map.named_route
>> map.named_route 'error_occurred', '/:controller/internal_server_error', {:action=>"resque"} => ANY /:controller/internal_server_error/ {:action=>"resque"}
map.namespace
>> map.namespace :admin do |admin| >> admin.resources :users >> admin.connect ':controller/:action/:id' >> end => GET /admin/users(.:format)? {:controller=>"admin/users", :action=>"index"} POST /admin/users(.:format)? {:controller=>"admin/users", :action=>"create"} GET /admin/users/new(.:format)? {:controller=>"admin/users", :action=>"new"} GET /admin/users/:id/edit(.:format)? {:controller=>"admin/users", :action=>"edit"} GET /admin/users/:id(.:format)? {:controller=>"admin/users", :action=>"show"} PUT /admin/users/:id(.:format)? {:controller=>"admin/users", :action=>"update"} DELETE /admin/users/:id(.:format)? {:controller=>"admin/users", :action=>"destroy"} ANY /admin/:controller/:action/:id/ {}
map.method_missing(定義されていないメソッド)
>> map.login '/login', :controller => 'sessions', :action => 'new' >> map.logout '/logout', :controller => 'sessions', :action => 'destroy' => ANY /login/ {:controller=>"sessions", :action=>"new"} ANY /logout/ {:controller=>"sessions", :action=>"destroy"}