【问题标题】:Rails: polymorphism vs. mixins vs. controller voodoo?Rails:多态性 vs. mixins vs. 控制器巫术?
【发布时间】:2011-10-04 06:49:26
【问题描述】:

所以,这里是它的缩写,这是一个新手问题,所以请耐心等待...我正在为我的公司构建一个公告板类型的应用程序作为 Rails 概念验证应用程序。

公告板正在替换现有功能,因此限制非常严格。最大的限制是内容分为三个级别:板、主题和回复。您无法回复回复(至少,系统不会为您提供帮助)——这是故意的,超出了本问题的范围。

现在,主题和回复具有共同的特点:它们都是用户生成的内容,都可以进行审核,有正文,由用户发布等。一位同事建议我简单地将这些对象设为一个称为“帖子”的概念的专业化,然后也将此帖子用于公告板(因为公告板也有标题和内容......长篇大论)。

所以我已经使用 post 模型构建了应用程序,并且我已经使用控制器和路由魔术完成了其他所有操作;我有一个 TopicsController 和一个 BoardsController(回复逻辑通过自定义操作在 TopicsController 内部处理)。我在路由文件中构建了嵌套命名空间,以便我可以执行以下操作:http://foo.com/boards/1/topics/2 等。

这位同事(他在我没有 Rails 的经验时有经验,所以我相信他的话)声称我应该做这个伪多态设计,因为我们最终会有其他内容——例如产品评论—— - 这将具有相似的内容(用户生成的文本,可能会被审核)- 如果我们可以简单地绑定到一个数据库表,那就容易多了。

他还建议我应该通过模块 mixins 在产品评论等中实现“额外”功能,而不是多态。我不确定这是对简单多态性或通过表连接实现的多态性(其中额外信息通过数据库关系绑定)实现的改进。

但是随着这个版本越来越大,我对此表示怀疑。只是……感觉不对。首先,虽然模型中存在多态性,但我不能 100% 确定最好的实现是什么;在某些方面,主题和回复有共同的元素 - 两者都有内容并且可以进行审核 - 但在其他方面它们非常不同(例如,回复没有主题)。而且板子甚至不是由最终用户创建的;它们是版主创建的。产品评论根本不像主题或回复。相反,它们与特定产品相关联。

我构建的越多,我就越觉得我们有“你所拥有的只是一把锤子”综合症;我们看到主题、回复、版块和产品评论看起来都“有点相似”,所以我们试图将它们强加到继承树中。事实上,我发现自己不得不越来越努力地对抗 Rails 框架,以添加自定义路由和操作、覆盖默认模型属性等等。

那么,我的问题是:社区对此有何看法?我们是否应该简单地为板、主题和回复提供单独的表格和模型?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3.1


    【解决方案1】:

    我的经验是,通常在 Rails 中使用多态性几乎总是一个错误。几乎每次我看到有人从它开始时,他们最终都会把它拉出来。

    我开始相信,模型越简单,通常就越好。所以对于这种类型的方法,我建议使用三个 ActiveRecord 类——Boards、Topics 和 Replies。

    另外,关于嵌套你的命名空间——你是否在你的路由文件中实现它作为嵌套资源?我建议不要使用命名空间。具体来说,我建议:

    resources :boards do
      resource :topics
    end    
    

    运行rake routes 这将为您提供以下路线:

         board_topics POST   /boards/:board_id/topics(.:format)      {:action=>"create", :controller=>"topics"}
     new_board_topics GET    /boards/:board_id/topics/new(.:format)  {:action=>"new", :controller=>"topics"}
    edit_board_topics GET    /boards/:board_id/topics/edit(.:format) {:action=>"edit", :controller=>"topics"}
                      GET    /boards/:board_id/topics(.:format)      {:action=>"show", :controller=>"topics"}
                      PUT    /boards/:board_id/topics(.:format)      {:action=>"update", :controller=>"topics"}
                      DELETE /boards/:board_id/topics(.:format)      {:action=>"destroy", :controller=>"topics"}
               boards GET    /boards(.:format)                       {:action=>"index", :controller=>"boards"}
                      POST   /boards(.:format)                       {:action=>"create", :controller=>"boards"}
            new_board GET    /boards/new(.:format)                   {:action=>"new", :controller=>"boards"}
           edit_board GET    /boards/:id/edit(.:format)              {:action=>"edit", :controller=>"boards"}
                board GET    /boards/:id(.:format)                   {:action=>"show", :controller=>"boards"}
                      PUT    /boards/:id(.:format)                   {:action=>"update", :controller=>"boards"}
                      DELETE /boards/:id(.:format)                   {:action=>"destroy", :controller=>"boards"}
    

    一般来说,每当您发现自己与 Rails 框架作斗争时,这就是一个明确的信号,表明您正在以艰难的方式做事。很好地感觉到这一点 - 并与你的直觉一起去。保持简单。

    【讨论】:

    • 谢谢;我是应用程序设计的老手,刚接触 Rails,并试图学习如何以“Rails 方式”构建事物。我们使用的是嵌套资源,而不是命名空间,顺便说一句——我的措辞草率。
    【解决方案2】:

    我肯定会将板子和产品评论保存为具有独立模型和控制器的单独数据库表。它们彼此之间确实有很大的不同,并且与主题和回复不同。用户生成的内容和审核等功能不依赖于多态性。只要列名相同,模型本质上是自动鸭型的。您可以仅将审核功能包含为控制器和/或模型模块混合,并假设相关对象将具有适当的属性以使审核工作。

    另一方面,主题和回复似乎是多态性的主要候选者(具体来说,我会使用单表继承)。如果我理解正确,这些主题和回复在所有方面几乎都是相同的,因此多态性将为您节省一些工作并防止错误(通过保持干燥)。

    一般来说,它就像你说的那样工作。如果你觉得你在反对框架的意见,那么你并没有真正充分利用框架,你应该重组你的设计以减少反对。

    免责声明:我不声称自己是 Rails 专家,但我也不是新手——毕竟,我确实有“ruby-on-rails”stackoverflow 徽章;)。我已经编写了几个应用程序,其中两个应用程序大量利用了多态性和模块混合,因此我在处理这种特殊类型的问题方面有相当多的经验。

    【讨论】:

    • 谢谢。我开始认为我绝对需要相信我的直觉。主题和回复绝对是多态性的候选者(是的,我可能只是去单表多态性),但是声称一个董事会“是一个”主题/回复是一个巨大的延伸,更糟糕的是试图延伸产品对此进行评论。
    【解决方案3】:

    首先,寻找合适的 Gem 可能是个好主意 - 有大量的 Gem 可以简化您的代码/编码。例如act_as_commentable、a​​cts_as_taggable、祖先等。

    你的问题的答案是:这取决于..

    如果您有需要强制执行的特定流程 - 例如。你需要有一个主题才能有评论,你需要有一个评论才能有回复..等等。

    使用多态自引用关联可能会起作用,但它会使您的设计更加复杂。 也许最好直接实现,每个模型都是自己的模型,然后在需要时对其进行改进。

    您可能还想看看“祖先”宝石,看看他们如何为祖先链建模,以便快速访问父母和孩子。

    检查这些 RailsCasts:

    糟糕……RailsCasts 目前已关闭……待续……

    第 163 集:自我参照关联

    检查http://www.railscasts.com/——有大量“带有评论和回复的博客文章”类型应用程序的示例

    【讨论】:

    • 我们现在正在使用acts_as_tree 在底层的post 对象中实现一个树结构(请记住,在当前实现中一切都是“post”,我们只是让它看起来与视图/控制器不同)。但这并不能真正解决板子、主题和回复是根本不同的问题,即使它们有共同点。
    • 附带说明:看看“ancestry” gem ,作为acts_as_tree 的替代品。它更有效地实现了树结构,并且访问速度更快..
    猜你喜欢
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 2010-10-29
    • 1970-01-01
    • 2010-09-14
    • 2011-01-25
    相关资源
    最近更新 更多