-
Notifications
You must be signed in to change notification settings - Fork 8
浜松rails3道場 routing編
浜松Rails3道場とは、習うより慣れろ方式で、Rails3のツボを浜松のRubyist達へ伝える試みである。
- Ruby on Rails Guides: Rails Routing from the Outside In
- RailsCasts - #203 Routing in Rails 3
- Ruby on Rails Documentation
練習用のRailsプロジェクトを作る。参考環境: Ruby 1.9.2, Rails 3.0.7
% rails new routing-dojo
% bundle install
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)
確認用のコントローラーを生成
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
- サーバーを起動しブラウザで確認
- 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"
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
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してみよう。
名前なきRoute使うべからず! 名前付きの方がトラブルが少なく、テストもしやすい。
Resource Routingを使うことによって、レストフルなURLを通じてリソースフルなコントローラーにアクセスするためのRouteを素早く宣言できる。index, show, new, edit, create, update, deleteといったリソースを操作するためのお決まりのRouteを幾つも書かなくても、たった1行で済ませることができる。
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で追加されたRouteは以下のような名前で呼び出すことができる。
products_path # => /products
new_product_path # => /products/new
edit_product_path(id) # => /products/:id/edit (例: edit_product_path(10) => /photos/10/edit)
product_path(id) # => /products/:id (例: product_path(10) => /products/10)
- Resource Routing によって呼び出される7つのアクションを持つProductsControllerを追加してみよう。
- 同じリクエストPathを持ち、HTTPメソッドが違うRouteはどうやって呼び出すのか考えよう。