我想我会将 STI 与有很多直通关系结合起来。
我将首先创建一个 Employers 和 Employees 的单表继承。
class User < ActiveRecord::Base
...
end
class Employer < User
end
class Employee < User
end
雇主雇用雇员。一个雇主可以有很多员工,并且随着就业而来的是其他相关属性,例如date_of_hire、designation、status、manager_id、department 等。因此我会将其建模为一个单独的对象,因此将此信息存储在一个单独的表。我们叫它Employment,好吗?
rails g model employment employer_id:integer, employee_id:integer, date_of_hire:date, designation:string, status:string, manager_id:integer
让我们现在建立关系。
class Employment < ActiveRecord::Base
belongs_to :employer # Foreign key options should not required because of User STI
belongs_to :employee
belongs_to :manager, :foreign_key => :manager_id, :class_name => "User"
end
class Employee < User
has_many :employments
has_many :employers
has_one :manager, :through => :employments, :foreign_key => :manager_id
end
class Employer < User
has_many :employments, :foreign_key => :employer_id
has_many :employees, :through => :employments
end
基于业务规则,我们可以实现优雅的作用域。
class Employee < User
...
scope :fired, :where => {:status => 'fired'}
scope :recently_joined, :where => {:date_of_hire => 3.months.ago...Date.today}
scope :developers, :where => {:designation => 'developer'}
...
end
还有……
Employee.recently_joined
Employee.recently_joined.developers
Employee.fired
请理解,这显然不是经过测试的代码,可能存在一些故障。
但是!
我强烈建议您重新考虑将雇主建模为用户的需求。从我个人的经验来看,后来证明是灾难(可能是我当时没有经验,但我不会再走那条路了)。我真的会为 Employer 和 Employee 建立单独的模型,并建立如上所述的关系,但使用 foreign_key 和 class_name 属性。主要原因是 STI 要在您的域中工作,雇主和雇员应该与用户具有“IS A”关系。您可能会认为这是一个“IS A”关系,但也认为它是否与“IS A”关系的“TYPE”相同。在我处理的应用程序中,它没有任何意义,但我们还是选择了 STI。雇主在申请中的特征、身份和待遇与雇员完全不同。尽管两者都有一些相同的数据,但它们的存在目的不同,用途也不同。这足以(单一职责)对它们进行单独建模。 STI 是一个可以解决问题的棘手工具。但是如果使用不当,会产生比它所能解决的问题更多的问题。