変数を含むパスの定義

Rails 3.2.2 で、パスに含まれる値を変数として扱うルーティングを定義したい時の記述方法について。
以下のサンプルではユーザの管理は User モデルで行い、必ず一意である name という値を持ち、ユーザ毎に Item モデルを操作可能だとします。

まずは routes.rb で次のように定義します。

scope "(:user_name)" do
  resources :items
end

ここで () をつけているのがポイントで、これが存在しない場合正しく動作しません。

この段階で params[:user_name] にパスの値が入るようになるのですが、せっかくなのでどこからでもデータにアクセスできるようにメソッドを定義しておきます。コントローラに以下のように記述します。

# coding: utf-8
class ApplicationController
  # 中略
  helper_method :current_user

  private
  def current_user
    @current_user ||= User.where(["name = ?", params[:user_name]]).first
  end
end

これでコントローラやビューから、現在指定されているユーザが誰なのか判別可能になりました。上の例では ApplicationController に記述しましたが、継承させたいコントローラが限られている場合などは適宜記述してください。
ビューから current_user を呼び出す時は、通常のヘルパメソッドのように記述すれば問題ありません。

<%= current_user.name %>

この状態で http://localhost:3000/bob/items にアクセスすると current_user は users.name = 'bob' なユーザに設定されます。

また、上記の例でデフォルト値を使いたい場合は、ルーティングをさらに変更します。

scope "(:user_name)", :default => {:user_name => "bob"} do
  resources :items
end

これでユーザの指定なしで http://localhost:3000/items にアクセスすると、自動的に http://localhost:3000/bob/items に繋いでくれます。

なお root を定義する時は scope の中で行います。

scope "(:user_name)", :default => {:user_name => "bob"} do
  root :to => "items#index"
  resources :items
end

これで http://localhost:3000 へのアクセスが http://localhost:3000/bob/items に変換されるようになりました。