route / map.resources の使い方

Rails 2.0 から標準になった、map.resources は RESTfulなコントローラに対応したrouting情報を作ってくれます。
ActiveResource が使えるようになり、外部とのRESTfulな操作が簡単にできてしまいます。
まだサンプル見た程度なので、機能は全部把握できていませんが。

参考 URL

http://d.hatena.ne.jp/zariganitosh/20080203/1202091772
http://rails-recipebook.g.hatena.ne.jp/rrbk/20071019
http://railspress.matake.jp/rails20%E3%81%AErouting%EF%BC%88configroutesrb%EF%BC%89%E3%81%AE%E8%A8%98%E8%BF%B0%E6%96%B9%E5%BC%8F%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81%E3%80%82
http://www.eisbahn.jp/yoichiro/2007/12/3mapresources.html

基本形

map.resources :books

redirect_to :controller => "books", :action => "index" などのようなパスを作成するには次のようにします。
※ @book はモデル

# index
books_path
books_url
# show
book_path(@book)  # もしくは id を指定
redirect_to @book
# new
new_book_path
# edit
edit_book_path(@book)
redirect_to [:edit, @book]   #redirect_to に渡す場合
# destroy
redirect_to book_path(@book), :method => :delete  # redirect_to に渡す場合

destroy だけちょっと面倒です。

多段な場合

map.resources :categories, :has_many => :books
map.resources :categories, :has_many => [:books, :authors] # 複数指定する場合は配列にする

※ :has_one もある。(map.resource になる)

  • 基本のパス生成は同じなので省略
  • books:

※@category, @book は各モデル

# index
category_books_path
# show
category_book_path(@category, @book)
link_to [@category, @books]   # link_to な場合
# new
new_category_book_path
# edit
edit_category_books_path(@category, @book) # …なぜかうまくいかないことがあった
link_to [:edit, @category, @book]
# destory
link_to category_book_path(@book), :method => :delete

やっぱり削除は面倒です。

コントローラを変える

  • 1モデル
map.resources :books, :controller => "published_books"
  • 多段の場合, has_many とかが使えないので次のようにする
map.resources :categories do |category|
  category.resources :books, :controller => "published_books"
end

生成されるパスを /categories/:id/books/ ではなくて、 /categories/:category_name/books のようにしたいとき

has_many, has_one は使えないので、次のようにします。
もちろん、 :category_name はユニークな値でないとおかしなことになります。

map.resources :categories
map.with_options :path_prefix => "/categories/:category_name", :name_prefix => "category_" do |categories|
  categories.resources :books
end

with_options ... do な形にしておけば、追加するときにDRYになります。


パスを生成するときの指定方法を次のようにする。

# index
category_books_path(:category_name => @category.name)
# show
category_book_path(:category_name => @category.name, :id => @book.id)
# edit
edit_category_book_path(:category_name => @category.name, :id => @book.id)
# destroy (redirect_to の場合)
redirect_to category_book_path(:category_name => @category.name, :id => @book.id), :method => :delete

コントローラもこちらの形式に対応させて書き直せば、若干面倒くさくなりますがとりあえず動作します。

map.namespace で プレフィックスをつける

パスの前に /admin を追加したい場合、map.namespaceを使えば簡単にできます。

map.namespace :admin do |admin|
  admin.resources :books
end

こうすると、コントローラは Admin::BooksController になり、パス生成も admin_books_path のようになります。