单表继承替代

时间:2013-12-24 18:13:44

标签: ruby-on-rails activerecord single-table-inheritance

我正在尝试使用STI在与described here非常相似的商业模式中思考。

class Person < ActiveRecord::Base
   # identified by email
end

class Owner < Person
end

class Customer < Person
end

class Employee < Person
end

class Store < ActiveRecord::Base
   belongs_to :owner
   has_many :customers
   has_many :employees
end

上面的课程描述了我打算做的事情。这里的问题是,员工永远不能充当客户,并且雇用他工作的商店或者甚至是其他商店提供的服务,除非创建新记录来代表作为不同角色的同一个人。上下文。那不是很干,但我不知道是否有更好的解决方案。

有吗?有人对我如何解决这个问题有任何建议吗?

非常感谢。

2 个答案:

答案 0 :(得分:3)

作为一个所有者(请注意,某个商店可能有几个,一个人可能拥有多个商店)不是一个人身份的一部分,它是一个人与商店之间的关系,所以子类化在这里并不合适。同样是作为客户或员工。

这给我们留下了五个组成部分:

  1. 商店。
  2. “人拥有商店”的关系。
  3. “人是商店的顾客”关系。
  4. “人是商店的雇员”关系。
  5. 实际上,这三种关系都是多对多关系。另请注意,STI随处可见;这是一件好事,STI几乎总是(IMO)是一个错误所以你应该在它出现时就开始询问你的数据模型和你的判断。 STI确实占有一席之地,但无论何时出现,你都应该认真思考。

    这给我们留下了两个相当简单的模型(PersonStore)以及人与商店之间的三对多关系。使用ActiveRecord建立多对多关系的标准方法是has_many ... :throughhas_and_belongs_to_many。如果您需要将其中一个人员关系作为一个单独的实体(例如具有员工编号,小时费率,税务记录等的员工),那么您可能需要has_many :through;如果您只需要关联,则has_and_belongs_to_many可能会有效。

    一些参考文献:

答案 1 :(得分:0)

实际上,从代码的角度来看,它是DRY。我实际上使用STI处理一个非常相似的项目,我们有用户,经理和管理员,数据库中每个都必须有三个记录。从Rails角度来看这是DRY,因为每个记录都有自己独特的属性,自己类中的方法等,但共享公共代码,从类似的模型到你所谓的Person 。我实际上认为如果你正在使用STI,这是一个很好的方法。

另一种方法是在模块中包含公共代码,您可以在CustomerEmployeeOwner中包含每个代码。

另一种替代方案(如果从头开始我最常做的事情)就是拥有一个Person表,并使用cancan甚至rolify来使用角色。通过这种方式,您可以使用一个名为Person的类,其中Person的实例可以包含一个或多个角色,例如customeremployee或{{ 1}}。