我知道STI是Rails社区(可能还有其他人)的争议主题,这也是我在走下STI路线之前试图找到不同解决方案的原因。
我正在构建一个具有联系人管理部分的系统,该部分包含client
和partner
条记录。区别在于partners
会有一个关联的partner_type
以及client
不会有的其他一些字段。
这看起来像STI的一个好例子。记录属于#34;类别",这意味着它们都代表"人员"但以不同的方式。它们都具有相同的核心字段,并且有许多email_addresses / phone_numbers。
但导致我转向STI而不是单独表的最大要求是,我需要按字母顺序列出所有联系人。我的雇主不希望单独的页面显示客户记录和合作伙伴记录。如果我把它分成多个表,我将不得不以某种方式查询两个表并按字母顺序排列它们,同时考虑到分页(每种类型将有数千条记录)。
STI之外还有其他解决方案吗?我知道很多开发人员之前遇到过STI的问题,但我倾向于这是一个教科书案例,其中STI实际上可以工作。
class Contact < ApplicationRecord
has_many :email_addresses # probably use polymorphic
has_many :phone_numbers # probably use polymorphic
validates :first_name, :last_name, presence: true
end
class Client < Contact
end
class Partner < Contact
belongs_to :partner_type
validates :partner_type, presence: true
# some attributes only applicable to client
validates :client_unique_field1, :client_unique_field2, presence: true
end
答案 0 :(得分:3)
在这种情况下,您需要做出两个设计决策:
partners
和clients
应该共享同一张桌子吗?
一个。如果“不”,那么您可以简单地创建单独的表和单独的模型。
湾如果“是”,那么你有第二个设计问题来回答#2。
partners
和clients
应该共享相同的模型类吗?
一个。如果“是”,那么您可以使用emum
来识别partner
和client
的不同角色,并使用enum
来推动您的业务逻辑。
湾如果“不”那么你应该实施STI。
我认为有充分理由对#1说“是”。似乎client
和partner
基本上都是一回事。他们都是人。
更重要的是,它们将包含大部分相同的信息,因此共享表格很有意义。
这样您就可以使用STI还是enum
。您需要做出的基本决策围绕与partners
和clients
相关联的业务逻辑。
如果大多数业务逻辑是共享的,那么使用enum
是有意义的。让我给你举个例子。在我的一个项目中,我有一个User
模型。所有用户都可以在网站上做基本的事情。不过,我们还有school_admin
个用户和class_admin
个用户。管理员当然可以更好地访问网站的某些部分,但从业务逻辑的角度来看,只有一些关系和一些方法是管理员独有的,而不是由用户共享。
由于95%的业务逻辑是在普通用户和管理员之间共享的,因此我选择将它们全部保存在一个类中。我使用名为enum
的{{1}}来区分用户:
role
在# in the User model
enum :role, [:graduate, :school_admin, :class_admin]
表格中,我有一个名为users
的{{1}}类型的列。 int
打开了一堆辅助方法,例如role
,以使业务逻辑工作。
您的情况可能有所不同。似乎enum
和class_admin?
可能会在您的应用中的业务逻辑上产生更大的差异。我不知道,但听起来他们的角色存在一些根本性的差异。您将必须决定它们之间共享多少业务逻辑以及有多少不同。如果它们足够不同,那么STI就有意义了。
此外,如果您希望利用方法中的继承,您可能希望使用STI路径。例如:您可能使用clients
方法,其中partners
具有与contact_verified?
不同的业务逻辑(可能是电子邮件和电话)(仅限电子邮件)。可能是一个弱小的例子,但你明白了。当然,使用单一模型方法时,您可以使用条件内partner.contact_verified?
完成相同的操作。
some in the Rails community tend to be down on STI你是对的。因此,不要轻易做出STI路线的决定。但是,我在一些与STI相关的问题很少的应用程序中成功使用了STI。
这一切都取决于共享多少业务逻辑以及是否要利用继承。决定最终取决于你。
答案 1 :(得分:2)
UNION
查询在SQL中轻松解决您的“最大”要求。
SELECT * FROM (SELECT id, 'Client' as type, first_name, last_name FROM clients
UNION SELECT id, 'Partner' as type, first_name, last_name FROM partners) AS t1
ORDER BY last_name LIMIT 25;
您可以更进一步INNER JOIN
电子邮件地址和电话号码。