首页 文章

Rails 4 [最佳实践]嵌套资源和浅:真

提问于
浏览
27

以下帖子基于Rails 4 .

我实际上正在寻找关于多个嵌套资源(超过1个)的良好最佳实践,并且选项浅:true .

首先在我的路线中,有这样的:

resources :projects do 
  resources :collections
end

相关的路线是:

project_collections GET    /projects/:project_id/collections(.:format)          collections#index
                        POST   /projects/:project_id/collections(.:format)          collections#create
 new_project_collection GET    /projects/:project_id/collections/new(.:format)      collections#new
edit_project_collection GET    /projects/:project_id/collections/:id/edit(.:format) collections#edit
     project_collection GET    /projects/:project_id/collections/:id(.:format)      collections#show
                        PATCH  /projects/:project_id/collections/:id(.:format)      collections#update
                        PUT    /projects/:project_id/collections/:id(.:format)      collections#update
                        DELETE /projects/:project_id/collections/:id(.:format)      collections#destroy
               projects GET    /projects(.:format)                                  projects#index
                        POST   /projects(.:format)                                  projects#create
            new_project GET    /projects/new(.:format)                              projects#new
           edit_project GET    /projects/:id/edit(.:format)                         projects#edit
                project GET    /projects/:id(.:format)                              projects#show
                        PATCH  /projects/:id(.:format)                              projects#update
                        PUT    /projects/:id(.:format)                              projects#update
                        DELETE /projects/:id(.:format)                              projects#destroy

我在文档中读到了嵌套资源的限制:

资源不应该嵌套超过1级 .

来源:http://guides.rubyonrails.org/routing.html#limits-to-nesting好的 . 然后,就像文档说的那样,我将在我的路线中使用"shallow" .

shallow do
  resources :projects do 
    resources :collections
  end
end

相关的路线是:

project_collections GET    /projects/:project_id/collections(.:format)     collections#index
                       POST   /projects/:project_id/collections(.:format)     collections#create
new_project_collection GET    /projects/:project_id/collections/new(.:format) collections#new
       edit_collection GET    /collections/:id/edit(.:format)                 collections#edit
            collection GET    /collections/:id(.:format)                      collections#show
                       PATCH  /collections/:id(.:format)                      collections#update
                       PUT    /collections/:id(.:format)                      collections#update
                       DELETE /collections/:id(.:format)                      collections#destroy
              projects GET    /projects(.:format)                             projects#index
                       POST   /projects(.:format)                             projects#create
           new_project GET    /projects/new(.:format)                         projects#new
          edit_project GET    /projects/:id/edit(.:format)                    projects#edit
               project GET    /projects/:id(.:format)                         projects#show
                       PATCH  /projects/:id(.:format)                         projects#update
                       PUT    /projects/:id(.:format)                         projects#update
                       DELETE /projects/:id(.:format)                         projects#destroy

我看到的主要区别是收藏品的“展示”,这个:

collection GET    /collections/:id(.:format)                      collections#show

所以如果我是对的,那么集合的show动作的链接是:

<%= link_to 'Show", collection_path(collection)%>

并应该返回这样的东西:“http://example.com/collections/1

但是! 2件事:

  • 这不起作用 . 我改为“http://example.com/projects/1” . WTF?

  • 即使它正在工作,它实际上也很糟糕,因为我放松了基本的"Collection is child of project, then the url should be " localhost / project / 1 / collections / 1

如果松开Rest动作的巨大优势,我不明白浅层的兴趣是什么 . 有什么兴趣?放松“表演”行动的兴趣是什么?我已经把它发布到了SO,但我得到的唯一评论是“这是正常的” . WTF?这是从其他API“删除”操作的正常行为?

我在一个中立项目上重现了这个问题,以确保我没有做错事,并且发生了同样的问题 . 所以,是的,帮助者使用浅层可能很方便,但对其余部分来说并不方便,你放松了“一个集合嵌套到一个项目中的所有兴趣,所以这反映在URL中” .

我不知道是否有另一种方法可以做到这一点,浅薄的是允许帮助者更多的灵活性,但是它的休息是否合规是错误的 . 那么,有没有机会让“助手”工作(拥有“nested3_path(collection)”而不是“nested1_nested2_nested3([nested1.nested2.nested3,nested1.nested2,nested1])”非常棒,并保持“ url part“并且一直有”nested1 / 123 / nested2 / 456 / nested3 / 789?

谢谢 !

5 回答

  • 1

    Levels

    您必须在嵌套资源中仅使用1级的概念才真正适用于系统的设计:

    相应的路径助手将是publisher_magazine_photo_url,要求您指定所有三个级别的对象 . 事实上,这种情况令人困惑,因为Jamis Buck的一篇热门文章提出了一个好的Rails设计的经验法则:

    我相信Rails仍然可以处理多个级别,尽管从可用性角度来看不建议使用它


    Shallow

    虽然我以前见过浅色,但我自己从未使用过它

    从查看documentation,它似乎浅薄有一个相当模糊的目的(我不在那里) . 问题是你没有公开将 post_id 参数传递给控制器,让你加载 collection 没有重要的参数

    我猜测(这只是推测),目的是通过你在幕后所需的参数,所以你留下了一条公共的“浅”路线:

    #config/routes.rb
    resources :projects do 
       resources :collections, shallow: true
    end
    

    我想你会得到一个这样的URL帮助:

    collection_path(project.id, collection.id)
    

    这将是 domain.com/collection/2

  • 2

    From this answer似乎浅薄的路线有点违背了Rails,IMO的惯例 .

    我认为你不需要显示路径的显式路径助手 . link_to帮助器应该能够从对象的to_param方法推断它 .

    #your helper becomes 
    link_to "show", collection
    

    如果您按照上面的方式使用帮助程序,则可能需要将父资源的嵌套ID传递给帮助程序 .

    link_to "show", collection_path([project, collection])
    
  • 20

    由于 CollectionCollection ,因此除了 indexcreate 动作之外,在项目下嵌套路径是多余的 .

    那里有's a rule about URL',你应该重定向到它 . 所以你可能有一个重定向到 /collections/:collection_id 的路由 /projects/:id/collections/:collection_id .

    在您的情况下,Collection与项目绑定,但对于所有关系而言并不一定如此 . 获得 :collection_id 之后,您无需引用 Project 的上下文来访问它 .

  • 2

    我不相信Rails提供任何内置方式让URL使用完整的层次结构(例如 /projects/1/collections/2 ),但也有快捷方式帮助程序(例如 collection_path 而不是 project_collection_path ) .

    如果你真的想这样做,你可以推出自己的自定义助手,如下所示:

    def collection_path(collection)
      # every collection record should have a reference to its parent project
      project_collection_path(collection.project, collection)
    end
    

    但是,对每个资源手动执行操作非常麻烦 .


    我认为使用 shallow 路线背后的想法最好由文档总结:

    避免深度嵌套的一种方法(如上所述)是生成在父级下作用域的集合操作,以便了解层次结构,但不嵌套成员操作 . 换句话说,仅构建具有最少量信息的路由以唯一地标识资源

    来源:http://guides.rubyonrails.org/routing.html#shallow-nesting因此,虽然这可能不符合REST(如您所说),但您不会丢失任何信息,因为每个资源都可以唯一标识,并且您可以在假设您的关联正确设置的情况下向后移动层次结构 .

  • 10

    虽然如果你只为某些型号需要它可能会使事情变得复杂,但最好还是查看Inherited Resources(IR) . 它支持资源嵌套,多态属于's, and can automatically generate the shorter path and url helper methods you are looking for. The reason you don'听到IR很多,因为它的原作者和其他一些开发人员因为尝试扩展控制器时出现的复杂性而有所放弃 . 但是,它仍然有一个社区,我们已经尝试将其扩展一点,并且更多地关注Irie的控制器扩展的简易性 .

    Rails中的“最佳实践”取决于您与谁交谈 .

    传统上,Rails主要针对(非嵌套)资源的基本CRUD . 是的,它允许检索和更新嵌套资源,但假设不会经常发生 .

    但是,Rails社区中出现的是ActiveModel::Serializers / json-api方法 . 在这种情况下,通常不会超过一级资源嵌套,嵌套资源可以是链接列表,也可以是子资源的侧载小版本,然后您可以在该资源上查询以获取更多数据 . 这也被Ember / Ember Data所接受 .

    还有一些其他项目旨在实现更接近罗伊菲尔丁最初的REST愿景的理解 .

    我认为这取决于您的设计是什么以及您需要什么 . 如果效率是一个目标,那么发展到明确和嵌套更多的额外时间可能会有所回报 . 例如,我们目前使用AngularJSIrie . 但每一个他自己 .

    与最后一点一样,请确保在查询中使用 includes(...) (或类似)来避免n 1次查找,否则所有嵌套都可能会影响您的性能 .

相关问题