5

我有许多不同的模型(接近 20 个),它们具有一些共同的属性,但在其他方面也有所不同。起初,STI 似乎很有吸引力,但我不知道随着时间的推移,随着产品的快速开发,各种模型将如何演变。

想到的与我们的应用程序类似的一个很好的例子是 Yelp。Yelp 如何在 Rails 中管理某些东西?所有的帖子都有一些共同的属性,比如“地址”。然而,它们在其他方面有很大不同。例如,您有餐厅的预订选项,而其他人可能没有。餐馆还有很多其他属性,比如“允许饮酒”,这些属性并不适用于其他人。用 STI 这样做会很快失控。

那么下一个最佳选择是什么?HStore 与 Postgres?除了小事之外,我不习惯使用 HStore。HStore 解决了一些问题,同时引入了其他一些问题,例如缺少数据类型、缺少引用完整性检查等。我想要一个可靠的关系数据库作为构建的基础。所以在 Yelp 的案例中,餐厅模式可能就是我要去的地方。我已经看过类似这里的建议 - http://mediumexposure.com/multiple-table-inheritance-active-record/,但我不乐意做这么多猴子补丁来获得如此普遍的东西。

所以我想知道还有哪些其他选择(如果有的话),还是我应该硬着头皮咬紧牙关,将这些共同属性复制到 20 个模型中?我认为我的问题将来自迁移文件而不是代码本身。例如,如果我将迁移设置为循环遍历表并在表上设置这些属性,那么我是否可以通过使用不同的模型来减轻问题的程度?

我是否忽略了一些关键的东西,可能会在未来使用单独的模型导致大量问题?

4

2 回答 2

6

我在这里看到几个选项:

  1. 咬紧牙关,创建 20 个具有许多相同属性的不同模型。这些模型可能会随着时间的推移而漂移 - 将新字段添加到一种特定类型 - 您将使用 STI 创建一个 200 列的表。也许你不知道——未来很难看到,尤其是探索性/敏捷软件。

  2. 将非引用字段存储在 NoSQL(文档)数据库中。将关系数据库用于关系的部分记录(用户有许多评论,而评论有一个业务),但将特定类型的内容保留在 NoSQL 数据库中。external_document_id在你的 Rails 模型和external_record_id/在你的 NoSQL 文档模式中保留一个,external_record_type这样你仍然可以使用你最终使用的任何 NoSQL ORM 查询所有允许吸烟的栏。

  3. 创建一个属性模型。belongs_to :parent_object, polymorphic: true带有keyandvalue字段的属性。使用这种方法,您可能有一个基本Business模型,并且每个企业都可以has_many :attributes。业务 ( ) 的某些(非关系?)属性allows_smoking是一个Attribute记录。的Attribute键可以是字符串,也可以是您拥有 Ruby 常量的数字。您实际上是在使用Attribute实体来创建选项 #2 的 SQL 版本。这可能是一个不错的选择,我自己将它用于用户或配置文件模型。(尽管使用这种方法需要注意一些性能问题)。

我真的很担心有这么多(独立)模型来处理听起来像子类的东西。有可能您可以通过使用关注点来干掉常见的行为/方法(mixin 概念上的语法糖,请参阅Rails 4 中关于关注点的一个很棒的 SO 答案)。当然,您仍然有(最初的)迁移问题。

于 2013-07-06T02:30:45.313 回答
1

在此处添加另一个选项:序列化 LOB (272)。ActiveRecord 允许您使用以下方法对对象执行此操作serialize

类用户 < ActiveRecord::Base 序列化 :preferences end

user = User.create(preferences: { "background" => "black", "display" => large }) User.find(user.id).preferences # => { "background" => "black", "显示" => 大 }

(来自ActiveRecord::Base文档的示例代码。)

要理解的重要结果是,存储在序列化 LOB 中的属性将不可索引,当然也不能以任何高性能方式进行搜索。如果您后来发现某个列需要可用作索引,您将不得不编写 [最有可能] 一个 Ruby 程序来执行转换(尽管默认情况下序列化是在 Yaml 中,因此任何 Yaml 解析器都足够了)。

优点是您无需对堆栈进行任何技术更改即可应用此模式。根据您收集的数据量,它很容易从这种模式中迁移出来。

于 2013-07-10T03:29:20.597 回答