scopeでtwitterっぽいルーティング

「Ruby on Rails 3 アプリケーションプログラミング」のルーティングの項をパラパラとめくっていたら、scopeを使ってtwitterっぽくトップレベル(?)にユーザ名を持ってくるようなルーティングができることを知ったのでメモ。

概要

例えばroutes.rbには次のように記述したとする。

scope ':uid' do
  resources :todos
end

このとき次のようなURLでアクセスすると、USERNAMEの部分をparams[:uid]で受け取ることができる。

http://scope-routing-sample.dev/USERNAME/todos

サンプルアプリを作ってみた

早速サンプルのTODOアプリを作ってgithubに上げてみた:scope-routing-sample

次の手順で動く、はず(bundler, rvm, pow, powderが導入済みの前提で)。

$ git cloen git@github.com:a2ikm/scope-routing-sample.git
$ cd scope-routing-sample
$ rvm use 1.8.7@scope-routing-sample --create
$ bundle
$ powder
$ rake db:migrate
$ open http://scope-routing-sample.dev/

開いたら、

  • 適当にユーザを登録(Uidは半角英数字がベター)
  • 一覧の画面でUidをクリックして開く
  • さぁURLを確認!

ハマったところ

app/views/todos/_form.html.erbにあるform_forがちょっと面倒くさかった。

ただのresourcesなら

form_for(@todo) do |f|

のような記述でよしなにやってもらえるんだけど、今回の場合には、

  • :uidに何が入るのかを指定する必要がある
  • Todoのインスタンスが保存済みか否かで:idを指定するか否かが変わる

ため、一工夫する必要があった(form_for and scopes, rails 3 - stackoverflowを参考にした)。

form_for(@todo, :url => (@todo.persisted? ? todo_path(:id => @todo.id, :uid => @uid) :
                                                 todos_path(:uid => params[:uid]))) do |f|

こうすることで、fには@todoに関するオブジェクトが入り、action属性のURLにはtodo_pathとtodos_pathが適宜切り替えられ、:idと:uidを指定することができる。

まとめ

  • scopeを使ったルーティングはカッコイイかもしれない
  • form_forで一工夫が必要

scopeをネストすればgithubみたいにUSERNAME/PROJECTNAMEみたいなURLも作れるのかな?今度試してみよう。