RailsでのfavoriteのURL設計
http://d.hatena.ne.jp/r7kamura/20110505/1304577667がすごいなと思って、routes.rbの書き方の例についてコメントしたのですが、自分で書いておいて後で「unfavorite」はちょっとまずいかなと思ったので、favorite(いわゆるお気に入り、スター)はどういうふうに設計すればいいのか考えてみました。
構造はよくある感じの、
tweet has_many favorites user has_many favorites
任意のツイートに任意のユーザーがお気に入りをつけられるというもの。別にツイートじゃなくても何でもOKです。
ブログのコメントにはこのように書きました。
(1)
resources :tweets do member do post 'favorite' post 'unfavorite' end end
ルーティングはこうなります。
favorite_tweet POST /tweets/:id/favorite(.:format) {:controller=>"tweets", :action=>"favorite"} unfavorite_tweet POST /tweets/:id/unfavorite(.:format) {:controller=>"tweets", :action=>"unfavorite"} tweets GET /tweets(.:format) {:controller=>"tweets", :action=>"index"} POST /tweets(.:format) {:controller=>"tweets", :action=>"create"} new_tweet GET /tweets/new(.:format) {:controller=>"tweets", :action=>"new"} edit_tweet GET /tweets/:id/edit(.:format) {:controller=>"tweets", :action=>"edit"} tweet GET /tweets/:id(.:format) {:controller=>"tweets", :action=>"show"} PUT /tweets/:id(.:format) {:controller=>"tweets", :action=>"update"} DELETE /tweets/:id(.:format) {:controller=>"tweets", :action=>"destroy"}
何がまずいのかというと、「"/tweets/:id/unfavorite"というURLがリソースの名前(基本的に名詞)になっていない」ということ。極端に言うと、GETできないURLがあったら何か変だというサインと思うのがいいかも。
"favorite"であれば名詞だし、これをPUTやDELETEすれば目的はかなうので、このようにするのがいいでしょう。
(2)
resources :tweets do resource :favorite, :only => [:update, :destroy] end
ここで中のメソッドが単数形"resource"なのに注意。ユーザが持つfavoriteはtweetごとに1個ずつしかないので、ここは単数リソースを使います*1。
:only をつけているのは、とりあえずPUTとDELETEしか必要ではないという理由です。さっきGETできないと変って言ってたんですが、例えばfavoriteをつけた日時などの属性情報を取得したいというニーズが出てくれば、GETで取得するのが自然なので、そのとき :only に :show を付け加えればいいわけです。
これによって、生成されるルーティングは以下の通り。
tweet_favorite PUT /tweets/:tweet_id/favorite(.:format) {:controller=>"favorites", :action=>"update"} DELETE /tweets/:tweet_id/favorite(.:format) {:controller=>"favorites", :action=>"destroy"} tweets GET /tweets(.:format) {:controller=>"tweets", :action=>"index"} POST /tweets(.:format) {:controller=>"tweets", :action=>"create"} new_tweet GET /tweets/new(.:format) {:controller=>"tweets", :action=>"new"} edit_tweet GET /tweets/:id/edit(.:format) {:controller=>"tweets", :action=>"edit"} tweet GET /tweets/:id(.:format) {:controller=>"tweets", :action=>"show"} PUT /tweets/:id(.:format) {:controller=>"tweets", :action=>"update"} DELETE /tweets/:id(.:format) {:controller=>"tweets", :action=>"destroy"}
と言ったけど
最初作るときは、あんまり深く考えず最初の(1)でもいいんではないかと。(1)から(2)はそんなに大きな変化ではないので、あとで見直して(2)に変更する手間もそんなにかからないと思います。
最初に大切なこと
それよりも、「できるだけresourcesを使う」ことのほうが大切だと思います。
routes.rbについて説明したページをいくつか読んだけど(代表はRails Routing from the Outside In — Ruby on Rails Guidesかな)、だいたい最初に基本という感じでmatchを説明しています。たしかに基本ではあるし直感的にわかりやすいのですが、多くの場合resourcesで用は足りるし、そういうときにmatch(get, post)を使うべきではありません*2。
まずresourcesに沿う形でURL設計を考えてみるのが「Railに乗りやすくなる」方法ではないかと思います。
参考文献
いつもの信頼の2冊。
Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)
- 作者: 山本陽平
- 出版社/メーカー: 技術評論社
- 発売日: 2010/04/08
- メディア: 単行本(ソフトカバー)
- 購入: 143人 クリック: 4,320回
- この商品を含むブログ (183件) を見る
- 作者: Leonard Richardson,Sam Ruby,山本陽平,株式会社クイープ
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2007/12/21
- メディア: 単行本
- 購入: 25人 クリック: 842回
- この商品を含むブログ (168件) を見る