Rails:PolyMorphic或STI或用户管理的其他东西?

nee*_*zer 6 ruby-on-rails polymorphic-associations sti

我一直在撞墙试图绕过这头,所以任何指导都会非常感激......

我想要一个用户系统设置来反映以下层次结构:

User
|- email address
|- password
|- billing information
|- contact information
|- account preferences
|
|=> Agent
|=> - agent-specific information
|=> - has_many Users
|=> - belongs_to Manager
|
|=> Manager
|=> - manager-specific information
|=> - has_many Agents, Users
|
|=> Administrator
|=> - can manage everything
Run Code Online (Sandbox Code Playgroud)

我已经有一个User使用DeviseCanCan设置的模型来处理身份验证和授权,所以我知道如何使用角色来限制用户的类型到特定的操作,等等.

我失去的是如何在我的Rails代码和数据库中组织这些子类关系.正如你可以看到从上面,Agent,Manager,和Administrator所有份额中包含的信息User,但每个都有一个与之相关的附加功能和信息.

我读过一些关于STI,多态关联自引用关联的知识.

如果我使用STI,该User表必须包含所有的我的[田Agent/ Manager/ Administrator]特定信息,对不对?这会让我的User桌子变得庞大,这是我想要避免的.相反,如果我使用多态,那么我不必复制所有User其他类型的User子类表中的所有公共信息吗?

并添加到我的困惑,我不能换我围绕如何回答上述问题将与子类之间的关系的工作头(如,一个Manager的has_many Agents,但两者的子类User...?).

我真的很感谢有人通过一个详细的答案让我直截了当,该答案适当考虑了代码的可读性和数据完整性,这简单地解释了(好像是一个Rails新手)为什么A是最好的方法,为什么B或n是 -通过比较 - 对于这种情况不是一个好的方法,并且提供了实现上述关系的示例代码.我想解决这个问题,但更重要的是,我要学习,为什么解决方案的工作!

iai*_*ain 8

我认为没有一个简单的解释为什么任何方法在任何情况下都是最好的.关于Stack Overflow的大量问题是关于如何设计模型之间关系的问题.这是一个复杂的主题,正确的解决方案需要对您正在解决的问题有深入的了解.即便如此,你可能也不会在前几次做对.

到目前为止,最好的方法是在这个问题上完全使用TDD/BDD,让测试/规格驱动你的设计.并且不要害怕重构你是否找到了更好的方法.大多数时候,只有在尝试了几个错误的解决方案之后才能看到正确的解决方案.你会了解边缘情况.正如沃德·坎宁安(Ward Cunningham)在其"技术债务"(Technical Debt)中所说的那样:" 事后重构就好像你从一开始就知道自己在做什么 ".尽管如此,请务必进行验收测试以验证其行为.

更具体地解决您的问题.还有第三个选项,即完全拆分类,每个类都有自己的表.我在我目前的项目中尝试过,我喜欢它.如果在您的业务领域中没有意义,则无需定义类似用户的内容.如果他们有共享行为,请使用mixins.最重要的警告是让他们再次通过相同的表单登录并不是直截了当的.

我有管理员,招聘人员,供应商和Visistor模型.它们都是独立的模型,与mixin共享一些行为.他们都有自己的命名空间控制器来行动.例如,管理员的所有操作都在Backend命名空间中.还有一个名称空间的ApplicationController.Backend :: ApplicationController只是指定before_filter :authorize_admin!.没有转换,没有复杂的案例陈述,没有.

你需要特别注意约定.如果您在模型中使用相同的名称,您的mixins可以变得非常简单.阅读ActiveSupport :: Concern以使mixins更易于使用.我有这样的mixin:

module Account
  extend ActiveSupport::Concern
  included do
    devise :database_authenticatable, :trackable, :recoverable, :rememberable
  end
end
Run Code Online (Sandbox Code Playgroud)

在我的路线:

devise_for :recruiters
devise_for :suppliers
# etc...
Run Code Online (Sandbox Code Playgroud)

app/controllers/backend/application_controller.rb看起来像这样:

class Backend::ApplicationController < ::ApplicationController
  layout "backend"
  before_filter :authenticate_admin!
  def current_ability
    @current_ability ||= AdminAbility.new(current_admin)
  end
end
Run Code Online (Sandbox Code Playgroud)

所以,总结一下.任何架构都可以.STI和多态性有其自己的位置,但一定要根据您的域建模您的架构.Ruby是一种非常灵活的语言,您可以利用它来获得优势.Devise和CanCan是出色的宝石,可以轻松应对这些情况.我向您展示了我正在进行的项目的解决方案.它适用于我,但我不能说它是否适合你.当你觉得自己做出了错误的决定时,不要害怕尝试和重构,而不是继续修补你原来的想法.

PS.说到STI和关系:它们也很好地协同工作.您可以定义从一个子类到另一个子类的关系.它将按预期工作.