在Rails 3中路由嵌套资源

时间:2011-02-17 04:26:07

标签: ruby-on-rails ruby ruby-on-rails-3 routing

我有一个非常常见的嵌套路由的情况,我觉得,看起来像这样(在某种伪语中):

'/: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一样。然而,在路线之后,事情变得更加复杂。在PhotosController #index动作中的条件变得越来越臃肿,并且正在进行大量的delgation。随着应用程序的增长以及我想要显示照片的方式的增加,它只会变得更糟。

选项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"}

我觉得这很好用,但是一切都在用户模块下,我觉得当我把它与其他东西集成时,最终可能会出现问题。

问题

  • 有没有人有这样的经历?
  • 任何人都可以分享更好的处理方法吗?
  • 使用其中任何一个选项可以考虑任何其他优缺点吗?

更新:我已经开始实施选项2,因为感觉更清晰,允许Rails的逻辑工作而不是覆盖它。到目前为止事情进展顺利,但我还需要将我的命名空间重命名为:users并添加:as => :user以防止它与我的User模型发生冲突。我还重写了to_param模型上的User方法以返回用户名。路径助手仍然以这种方式工作。

我仍然感谢您对这种方法的反馈。我是按照预期的方式做事,还是我滥用了这个功能?

5 个答案:

答案 0 :(得分:7)

在这种情况下,您是否考虑过使用浅层嵌套路线?

浅路嵌套 有时,嵌套资源会产生繁琐的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)

答案 1 :(得分:6)

执行此操作的最佳方式取决于应用程序,但在我的情况下,它肯定是选项B.使用命名空间路由我能够使用模块以非常干净的方式将不同的关注点分离到不同的控制器中。我还使用特定于命名空间的控制器向特定命名空间中的所有控制器添加共享功能(例如,添加一个before_filter来检查命名空间中所有资源的身份验证和权限)。

答案 2 :(得分: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

答案 3 :(得分:0)

您可以为一位用户定义一条单独的路线,如下所示:

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

但我建议只使用Jimmy上面发布的嵌套资源,因为这是最灵活的解决方案。

答案 4 :(得分:0)

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

刚刚在我当前的项目中应用它。