Rails:使用 STI 为客户和合作伙伴记录建模
Rails: using STI to model client and partner records
我知道 STI 是 Rails 社区(可能还有其他人)中的一个有争议的话题,这就是我在走 STI 路线之前试图找到解决我的问题的不同方法的原因。
我正在构建一个具有联系人管理部分的系统,其中包含 client
和 partner
记录。不同之处在于 partners
将有一个关联的 partner_type
和一些 client
没有的附加字段。
这看起来是 STI 的一个好案例。这些记录是相同的 "category",这意味着它们都代表 "people",但方式不同。他们都会有相同的核心领域,并且有很多 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
您需要做出两个设计决定来实现此案例:
partners
和clients
是否应该共享相同的table?
一个。如果 "no",那么您只需创建单独的 table 和单独的模型。
b。如果 "yes",那么您还有第二个设计问题要回答 #2。
partners
和clients
是否应该共用同一个模型class?
一个。如果 "yes",那么您可以使用 emum
来识别 partner
和 client
的不同角色,并使用 enum
来驱动您的业务逻辑。
b。如果 "no" 那么您应该实施 STI。
我认为对#1 说 "yes" 是有充分理由的。看来 client
和 partner
从根本上讲是同一回事。他们都是人。
更重要的是,它们将包含大部分相同的信息,因此共享 table 很有意义。
因此,您将决定是使用 STI 还是 enum
。您需要围绕与 partners
和 clients
.
相关的业务逻辑做出基本决策
如果大部分业务逻辑是共享的,那么使用 enum
是有意义的。让我举一个例子。在我的一个项目中,我有一个 User
模型。所有用户都可以在网站上做基本的事情。但是,我们也有 school_admin
个用户和 class_admin
个用户。管理员当然对网站的某些部分有更多的访问权限,但从业务逻辑的角度来看,只有几个关系和几个方法是管理员独有的,用户不共享。
由于 95% 的业务逻辑由普通用户和管理员共享,因此我选择将它们全部集中在一起 class。我用了一个叫role
的enum
来区分用户:
# in the User model
enum :role, [:graduate, :school_admin, :class_admin]
在 users
table 中,我有一个名为 role
的 int
类型的列。 enum
开辟了一堆辅助方法,比如class_admin?
,让业务逻辑正常工作。
您的情况可能有所不同。看来 clients
和 partners
在您的应用程序中的业务逻辑可能有更大的差异。我不知道,但听起来他们的角色存在一些根本差异。您将必须决定它们之间共享多少业务逻辑以及有多少不同。如果它们足够不同,那么 STI 就有意义。
此外,如果您想在方法中利用继承,您可能想要走 STI 路线。例如:您可能有一个 contact_verified?
方法,其中 partner.contact_verified?
与 client.contact_verified?
(仅电子邮件)具有不同的业务逻辑(电子邮件和 phone 可能)。也许是一个薄弱的例子,但你明白了。当然,在使用单一模型方法时,您可以在 contact_verified?
内部使用条件来完成同样的事情。
你说得对some in the Rails community tend to be down on STI。所以不要轻易决定走 STI 路线。但是,我在一些应用程序中成功地使用了 STI,几乎没有出现与 STI 相关的问题。
这完全取决于共享多少业务逻辑以及是否要利用继承。最终决定权在您。
Tom Aranda 提供了一个很好的框架来决定一种方法(看起来你应该使用一个 table)。但是,即使您决定使用两个 table,您的 "biggest" 要求也可以通过 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
电子邮件地址和 phone 号码。
我知道 STI 是 Rails 社区(可能还有其他人)中的一个有争议的话题,这就是我在走 STI 路线之前试图找到解决我的问题的不同方法的原因。
我正在构建一个具有联系人管理部分的系统,其中包含 client
和 partner
记录。不同之处在于 partners
将有一个关联的 partner_type
和一些 client
没有的附加字段。
这看起来是 STI 的一个好案例。这些记录是相同的 "category",这意味着它们都代表 "people",但方式不同。他们都会有相同的核心领域,并且有很多 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
您需要做出两个设计决定来实现此案例:
partners
和clients
是否应该共享相同的table?一个。如果 "no",那么您只需创建单独的 table 和单独的模型。
b。如果 "yes",那么您还有第二个设计问题要回答 #2。
partners
和clients
是否应该共用同一个模型class?一个。如果 "yes",那么您可以使用
emum
来识别partner
和client
的不同角色,并使用enum
来驱动您的业务逻辑。b。如果 "no" 那么您应该实施 STI。
我认为对#1 说 "yes" 是有充分理由的。看来 client
和 partner
从根本上讲是同一回事。他们都是人。
更重要的是,它们将包含大部分相同的信息,因此共享 table 很有意义。
因此,您将决定是使用 STI 还是 enum
。您需要围绕与 partners
和 clients
.
如果大部分业务逻辑是共享的,那么使用 enum
是有意义的。让我举一个例子。在我的一个项目中,我有一个 User
模型。所有用户都可以在网站上做基本的事情。但是,我们也有 school_admin
个用户和 class_admin
个用户。管理员当然对网站的某些部分有更多的访问权限,但从业务逻辑的角度来看,只有几个关系和几个方法是管理员独有的,用户不共享。
由于 95% 的业务逻辑由普通用户和管理员共享,因此我选择将它们全部集中在一起 class。我用了一个叫role
的enum
来区分用户:
# in the User model
enum :role, [:graduate, :school_admin, :class_admin]
在 users
table 中,我有一个名为 role
的 int
类型的列。 enum
开辟了一堆辅助方法,比如class_admin?
,让业务逻辑正常工作。
您的情况可能有所不同。看来 clients
和 partners
在您的应用程序中的业务逻辑可能有更大的差异。我不知道,但听起来他们的角色存在一些根本差异。您将必须决定它们之间共享多少业务逻辑以及有多少不同。如果它们足够不同,那么 STI 就有意义。
此外,如果您想在方法中利用继承,您可能想要走 STI 路线。例如:您可能有一个 contact_verified?
方法,其中 partner.contact_verified?
与 client.contact_verified?
(仅电子邮件)具有不同的业务逻辑(电子邮件和 phone 可能)。也许是一个薄弱的例子,但你明白了。当然,在使用单一模型方法时,您可以在 contact_verified?
内部使用条件来完成同样的事情。
你说得对some in the Rails community tend to be down on STI。所以不要轻易决定走 STI 路线。但是,我在一些应用程序中成功地使用了 STI,几乎没有出现与 STI 相关的问题。
这完全取决于共享多少业务逻辑以及是否要利用继承。最终决定权在您。
Tom Aranda 提供了一个很好的框架来决定一种方法(看起来你应该使用一个 table)。但是,即使您决定使用两个 table,您的 "biggest" 要求也可以通过 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
电子邮件地址和 phone 号码。