web-dev-qa-db-ja.com

ネストされたリソースのルーティングRails 3

ネストされたルートのかなり一般的なケースがあります、これは次のようなものです(ある種の疑似表記):

'/:username/photos' => Show photos for User.find_by_username
'/photos' => Show photos for User.all

一言で言えば:ユーザーがいます。彼らは写真を持っています。彼らの写真を彼らのページに表示したいです。また、ユーザーに関係なく、すべての写真を表示できるようにしたいと考えています。ルートをRESTfulに保ち、組み込みのresourceメソッドを使用することは、正しい方法のように感じます。


オプション1これを行うには、PhotosController#indexに条件を使用して、指定されたパラメーターを確認し、写真のリストを取得してビューを設定します(すべての写真よりもユーザーの写真では異なります)。ルーティングも簡単です。

resources :photos, :only => [:index]
scope ':/username' do
  resources :photos
end

ブーム。 Railsはこのように設定されていましたが、ルートの後は、状況はさらに複雑になります。それはseemのようです。 PhotosController#indexアクションの条件付きのバックは、ますます肥大化し、ひどく多くの分析を行っています。アプリケーションが成長し、写真を表示する方法の数が増えるにつれて、状況は悪化するだけです。

オプション2は、ユーザーの写真を処理するためのUser :: PhotosControllerと、すべての写真の表示を処理するためのPhotosControllerを持つことです。

resources :photos, :only => [:index]
namespace :user, :path => '/:username' do
  resources :photos
end

これにより、次のルートが生成されます。

           photos GET    /photos(.:format)                    {:action=>"index", :controller=>"photos"}
      user_photos GET    /:username/photos(.:format)          {:action=>"index", :controller=>"user/photos"}
                  POST   /:username/photos(.:format)          {:action=>"create", :controller=>"user/photos"}
   new_user_photo GET    /:username/photos/new(.:format)      {:action=>"new", :controller=>"user/photos"}
  edit_user_photo GET    /:username/photos/:id/edit(.:format) {:action=>"edit", :controller=>"user/photos"}
       user_photo GET    /:username/photos/:id(.:format)      {:action=>"show", :controller=>"user/photos"}
                  PUT    /:username/photos/:id(.:format)      {:action=>"update", :controller=>"user/photos"}
                  DELETE /:username/photos/:id(.:format)      {:action=>"destroy", :controller=>"user/photos"}

これはかなりうまくいくと思いますが、すべてがUserモジュールの下にあり、他のものと統合すると問題が発生する可能性があるように感じます。

ご質問

  • 誰かがこのようなことを経験したことがありますか?
  • 誰かがこれを処理するより良い方法を共有できますか?
  • これらのオプションのいずれかで検討すべき追加の長所と短所はありますか?

pdate:Railsのロジックをオーバーライドするのではなく機能させるのをよりクリーンに感じるので、オプション2の実装を進めました。これまでのところ順調ですが、名前空間の名前を:usersに変更し、:as => :userを追加して、Userモデルと競合しないようにする必要もあります。ユーザー名を返すために、Userモデルのto_paramメソッドもオーバーライドしました。パスヘルパーもこのように機能します。

この方法についてのフィードバックをお待ちしています。私は物事を期待どおりにやっていますか、それともこの機能を誤用していますか?

33
coreyward

これを行う最適な方法はアプリケーションによって異なりますが、私の場合は確かにオプションBです。名前空間付きルートを使用すると、モジュールを使用してさまざまな懸念事項をさまざまなコントローラーに非常にクリーンな方法で分離できます。また、名前空間固有のコントローラーを使用して、特定の名前空間のすべてのコントローラーに共有機能を追加しています(たとえば、before_filterを追加して、名前空間のすべてのリソースの認証と権限を確認しています)。

6
coreyward

この場合、浅いネストされたルートの使用を検討しましたか?

浅いルートの入れ子入れ子になったリソースは、扱いにくいURLを生成することがあります。これに対する解決策は、浅いルートのネストを使用することです。

resources :products, :shallow => true do
  resources :reviews
end

これにより、次のルートを認識できるようになります。

/products/1 => product_path(1)
/products/1/reviews => product_reviews_index_path(1)
/reviews/2 => reviews_path(2)
7
MattMcKnight

私は自分のアプリの1つでこれと同様のことをしました。あなたは正しい軌道に乗っています。私が行ったのは、ネストされたリソースを宣言し、Rails 3.でActive Recordの柔軟なarelベースの構文を使用してクエリを作成することです。

# config/routes.rb
resources :photos, :only => :index
resources :users do
  resources :photos
end

# app/controllers/photos_controller.rb
def index
  @photos = Photo.scoped
  @photos = @photos.by_user(params[:user_id]) if params[:user_id]
  # ...
end
1
Jimmy Cuadra
Example::Application.routes.draw do
  resources :accounts, :path => '' do
    resources :projects, :path => '', :except => [:index]
  end
end

例を以下に示します: http://jasoncodes.com/posts/Rails-3-nested-resource-slugs

私の現在のプロジェクトでそれを適用しました。

0
Arthur Corenzan

次のように、1人のユーザーの写真を取得するための別のルートを定義できます。

get '(:username)/photos', :to => 'photos#index'

しかし、ジミーが上記で投稿したネストされたリソースを使用することをお勧めします。これが最も柔軟なソリューションだからです。

0
Martijn