Rails 3のルーティングで気になったところについて。いつものメモです。あくまで気になったところなので全部網羅しているわけではありません。あしからず。
基本形
map.connect から match メソッドに変更。オプションも下記のように変更。
# Rails 2 map.connect 'products/:id', :controller => 'products', :action => 'view' # Rails 3 match 'products/:id', :to => 'catalog#view' # :to は省略可能 match "/account" => "account#index" # :controller/:action 形式であればさらに省略可能 match "account/overview"
Named Routes
asオプションで指定するように変更になった。
# Rails 2 map.logout '/logout', :controller => 'sessions', :action => 'destroy' # Rails 3 match 'logout', :to => 'sessions#destroy', :as => "logout"
メソッドの指定
get(post,put,delete)メソッドで指定できるように。またはviaオプションで。
# Rails 2 map.connect "account/overview", :controller => "account", :action => "overview", :conditions => {:method => :get } # Rails 3 get "account/overview" # または:viaオプションで指定 match "account/overview", :to => "account#overview", :via => :get
デフォルトパラメータの指定
defaults オプションでデフォルトで渡すパラメータを指定できる
match 'photos/:id' => 'photos#show', :defaults => { :format => 'jpg' }
RESTfulなルーティング
resourcesには複数の引数が渡せる(これはRails 2 からできたみたい)
resources :photos, :books, :videos
これまでresourcesメソッドのオプションとして扱われていたものがブロック内のメソッドとして使えるように。
resources :products do collection do get :sold post :on_offer end end
インラインでも指定出来る
resources :products do get :sold, :on => :member end
resourcesで出来るアクションのルーティングをブロックの中で上書きすることが出来るみたい。
resources :sessions do get :create end
asオプションを使うとnamed routesの名前を変更できる
# devices_url で products#index にアクセスできる resources :products, :as => 'devices'
pathも変えたければ下記のようにする
# /devices にアクセスすると products#index へ resources :devices, :controller => "products"
onlyとexceptで不必要なルーティングを作成しないように出来る(これは Rails 2.2.1 以降 と 3 で共通)
resources :posts, :except => [:index]
Resourceのネストは Rails 2 と 3 で同じ。
resources :projects do resources :tasks, :people end
singularも Rails 2と同じ
resources :teeth, :singular => "tooth"
Namespaceを定義
Admin::PostsController 用のRESTfulなルーティングは下記のように定義できる
namespace :admin do resources :posts end
パスは /admin/posts みたいになる。/admin を削除したければ下記のようにする。
scope :module => "admin" do resources :posts, :comments end
一行で書きたい場合は下記のようにする。
resources :posts, :module => "admin"
逆に/admin/photosでPostsControllerにアクセスしたいときは下記のようにする
scope "/admin" do resources :posts, :comments end
一行で書きたいときには下記のようにする
resources :posts, :path => "/admin"
newやeditのアクションのパスを変更するにはpath_namesオプションを使う。
resources :projects, :path_names => { :edit => 'cambiar' }
scope を使えばブロック中全部のルーティングに適用できる
scope :path_names => { :new => "make" } do # rest of your routes end
リダイレクト
redirectメソッドを使うことで、ルーティング上でリダイレクトを設定できる。ただし他のメソッドと違い、ブロック中では使えないらしい。
# /foo/1 にアクセスしたら /bar/1sにリダイレクトする match "/foo/:id" => redirect("/bar/%{id}s") # /account/proc/john にアクセスしたら /johnsにリダイレクトする match 'account/proc/:name' => redirect {|params| "/#{params[:name].pluralize}" } # request オブジェクトもブロックパラメータとして渡せる match "/stories" => redirect {|p, req| "/posts/#{req.subdomain}" }
Rack
ルーティング先にRackアプリケーションを指定できる。
match "/application.js" => Sprockets
"posts#index"のように指定したときは、最終的にRackアプリを返す PostsController.action(:index) が呼ばれるようになっているので全部のルーティングで最終的には Rack アプリが指定されていることになる。
Constraints
requirements オプションから constraints オプションに変わった。
match "/posts/show/:id" => "posts#index", :constraints => {:id => /\d/}
上記のような場合はconstraintsを省略できる
match "/posts/show/:id" => "posts#index", :id => /\d/
resources なルーティングには id の constraints がかけられる。
resources :photos, :constraints => {:id => /[A-Z][A-Z][0-9]+/}
もちろんブロックをとるメソッドも用意されている
constraints(:id => /[A-Z][A-Z][0-9]+/) do resources :photos resources :accounts end
Requestオブジェクトのメソッドのうち、Stringを返す全てのメソッドに constraints を設定できる。例えば、Request#subdomainが定義されているので、下記のようにするとサブドメインを利用したルーティング定義が出来る*1
match "photo", :constraints => {:subdomain => "admin"}
RegExpもキーにとれる
match "photo", :constraints => {:subdomain => /user/}
もちろんブロックをとるメソッドも用意されている
namespace "admin" do constraints :subdomain => "admin" do resources :photos end end
constraints 用のオブジェクトを作ってルーティングに使用することが出来る。オブジェクトはmathces?が定義されていればあとは特に条件はないみたい。
class BlacklistConstraint def initialize @ips = Blacklist.retrieve_ips end def matches?(request) @ips.include?(request.remote_ip) end end TwitterClone::Application.routes.draw do match "*path" => "blacklist#index", :constraints => BlacklistConstraint.new end
オプション
括弧でくくったパスはオプションとして扱われる
match 'posts(/new)', :to => 'posts#create'
残り全部とマッチさせる
残り全部とマッチさせる書き方は Rails 2 と同じくアスタリスクを使う。
match 'photo/*other' => 'photos#unknown'
/photo 以下のパスは params[:other] に入る。
感想
Rails 3のルーティング定義は、2の頃ではできなかったいろんな書き方が定義されてこれまで複雑な記述をしていた定義がエレガントに書けるようになり嬉しい反面、出来ることが多すぎて覚えるのが大変そうですね><