Skip to content

浜松rails3道場 routing編

mackato edited this page May 11, 2011 · 39 revisions

浜松Rails3道場とは、習うより慣れろ方式で、Rails3のツボを浜松のRubyist達へ伝える試みである。

Routing編

参考

前準備

練習用のRailsプロジェクトを作る。参考環境: Ruby 1.9.2, Rails 3.0.7

% rails new routing-dojo
% bundle install

Routingとは

HTTPリクエスト(URL、メソッド)を受け取って、コントローラーのアクションを呼び出す仕組み。また、パスやURLを生成し文字列によるこれらのハードコードを回避することができる。

The Rails router recognizes URLs and dispatches them to a controller’s action. It can also generate paths and URLs, avoiding the need to hardcode strings in your views.(Ruby on Rails Guides)

Routingを使う

確認用のコントローラーを生成

rails g controller catalog view

設定ファイルにrouteを追加する。

# config/routes.rb
match 'products/:id' => 'catalog#view'

Viewで使う

<% # app/views/catalog/view.html.erb %>
<%= link_to 'Product: 2', :controller => 'catalog', :action => 'view', :id => 2 %>

Controllerで使う

# app/controllers/catalog_controller.rb
redirect_to :controller => 'catalog', :action => 'view', :id => 3

Routingを確認する

  • サーバーを起動しブラウザで確認
  • rake routes タスクで確認
  • rails console コマンドで確認
  • テストを書いて確認

コンソールで確認

% rake routes
...
/products/:id(.:format)          {:controller=>"catalog", :action=>"view"}
...
% rails console
Loading development environment (Rails 3.0.7)
> r = ActionController::Routing::Routes
> r.recognize_path '/products/1'
 => {:controller=>"catalog", :action=>"view", :id=>"1"}
> r.generate :controller => 'catalog', :action => 'view', :id => '2' 
 => "/products/2"

Routingのテスト

Railsのコントローラーのテストでは、Routingをテストするための3種類のビルトインアサーションが用意されている。

# test/functional/catalog_controller_test.rb

# assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)
assert_generates "/products/1", :controller => 'catalog', :action => 'view', :id => '1'

# assert_recognizes(expected_options, path, extras={}, message=nil)
assert_recognizes({ :controller => "catalog", :action => "view", :id => "2" }, "/products/2")

# assert_routing(path, options, defaults={}, extras={}, message=nil)
assert_routing "/products/3", { :controller => "catalog", :action => "view", :id => "3" }

url_forなどを使いビューのテストでも検証することができる。

# test/unit/helpers/catalog_helper_test.rb
assert_equal '/products/1', url_for(:controller => 'catalog', :action => 'view', :id => '1')

試してみよう!

  • 'products/:id' の productsと:id の部分を変更してみよう。
  • ビューで :controller や :action などのキーをTypoしてみよう。

参考

Test::Unitの代わりにRSpecを使うと専用のRouting specsが生成される。

# spec/routing/catalog_routing.spec
describe "routing to catalog" do
  it "routes /products/:id to catalog#show for id" do
    { :get => "/products/1" }.should route_to(
      :controller => "catalog",
      :action => "view",
      :id => "1"
    )
  end
end

Named routes

Routeには名前を付けることができる。

# config/routes.rb
match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase

# test/functional/catalog_controller_test.rb
assert_equal "/products/1/purchase", purchase_path(:id => '1')
assert_equal "http://test.host/products/2/purchase", purchase_url(:id => 2)

アプリケーションのrootでは専用のショートカットが使える。

root :to => "welcome#index" # root_path => '/'

試してみよう!

  • 'catalog#view' へのRoutingにも名前を付けてみよう。
  • ビューでxxx_path, xxx_url をTypoしてみよう。

教訓その1

名前なきRoute使うべからず! 名前付きの方がトラブルが少なく、テストもしやすい。

Resource Routing: the Rails標準

Resource Routingを使うことによって、レストフルなURLを通じてリソースフルなコントローラーにアクセスするためのRouteを素早く宣言できる。index, show, new, edit, create, update, deleteといったリソースを操作するためのお決まりのRouteを幾つも書かなくても、たった1行で済ませることができる。

Resource Routingの規約

RailsではResource Routingの規約に基づいて、HTTPメソッドとURLをコントローラーのアクションにマッピングする。

まず、設定ファイルに以下のようなRouteを追加する。

# config/route.rb
resources :products

これにより、PruductsControllerの7つのアクションとHTTPリクエストをマッピングする以下のようなRouteが追加される。

HTTPメソッド リクエストPath アクション 一般的な動作
GET /products index Productのリストを表示する
GET /products/new new 新しいProductを追加するためのフォームを表示する
POST /products create 新しいProductを作成する
GET /products/:id show 指定されたProductを表示する
GET /products/:id/edit edit 指定されたProductを編集するためのフォームを表示する
PUT /products/:id update 指定されたProductを更新する
DELETE /products/:id destroy 指定されたProductを削除する

Resource RoutingのPathとURL

Resource Routingで追加されたRouteは以下のような名前で呼び出すことができる。

products_path  # => /products
new_product_path # => /products/new
edit_product_path(id) # => /products/:id/edit (例: edit_product_path(10) => /products/10/edit)
product_path(id) # => /products/:id (例: product_path(10) => /products/10)

試してみよう!

  • Resource Routing によって呼び出される7つのアクションを持つProductsControllerを追加してみよう。
  • 同じリクエストPathを持ち、HTTPメソッドが違うRouteへのリンクをビューに追加してみよう。

教訓その2

可能なかぎりResource Routingを使うべし! 名前付けで悩まなくてすむ。規約により共通の理解が得やすい。Scaffoldがそのまま使える。

ネームスペース付きのRouting

複数のコントローラーを単一のネームスペースに配置したい場合がある。例えば、管理者用に幾つかのリソースフルなコントローラーを Admin::ネームスペースに配置したいとする。つまり、 app/controllers/admin ディレクトリの中にコントローラーを作成した場合は以下のように記述すれば良い。

namespace :admin do
  resources :products
end

これにより、以下のようなRouteが追加される。

HTTPメソッド リクエストPath アクション ヘルパー
GET /admin/products index admin_products_path
GET /admin/products/new new new_admin_product_path
POST /admin/products create admin_products_path
GET /admin/products/1 show admin_product_path(id)
GET /admin/products/1/edit edit edit_admin_product_path(id)
PUT /admin/products/1 update admin_product_path(id)
DELETE /admin/products/1 destroy admin_product_path(id)

Nested Resources

Creating Paths and URLs From Objects

Adding More RESTful Actions

Customizing Resourceful Routes

Specifying a Controller to Use

Specifying Constraints

Overriding the Named Helpers

Overriding the new and edit Segments

Prefixing the Named Route Helpers

Restricting the Routes Created

Translated Paths

Overriding the Singular Form

Using :as in Nested Resources

Clone this wiki locally