Ruby on Rails - 有没有STI的替代方案?

20 浏览
0 Comments

Ruby on Rails - 有没有STI的替代方案?

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

一个很好的类比我们应用程序的例子是Yelp。Yelp如何在Rails中管理呢?所有的帖子都有一些共同的属性,比如“地址”。然而,它们在其他方面有很大的差异。例如,你可以为餐馆预定,但可能不是其他类型的商家。餐馆还有许多其他属性,比如“允许酒精”,这些属性并不适用于其他商家。使用STI做这件事很快就会失控。

那么接下来最好的选择是什么?Postgres中的HStore?我不舒服地使用HStore做除小事以外的其他事情。虽然HStore解决了一些问题,但也引入了其他问题,比如缺少数据类型,缺少参照完整性检查等。我想要一个坚实的关系数据库作为基础进行建立。因此,在Yelp的情况下,可能是一个餐馆模型是我所要去的地方。我看了一些类似这样的建议 - http://mediumexposure.com/multiple-table-inheritance-active-record/,但我不高兴要做太多的monkey patching来实现这么常见的事情。

所以,我想知道还有没有其他的替代方案(如果有的话),或者我应该咬紧牙关,复制这20个模型中的共同属性?我认为我的问题会来自于迁移文件,而不是代码本身。例如,如果我设置我的迁移来循环遍历表,并在表上设置这些属性,那么我是否已经缓解了具有不同模型的问题的程度?

我是否忽略了一些重要的事情,可能会在将来使用分开的模型时造成大量问题?

admin 更改状态以发布 2023年5月21日
0
0 Comments

在这里添加另一个选项:Serialized LOB (272)。 ActiveRecord 允许您使用 serialize 对对象进行如下操作:

class User < ActiveRecord::Base serialize :preferences end

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

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

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

优点是您不必对堆栈进行任何技术更改,即可将此模式应用于您的项目。根据您收集的数据量,很容易将其迁移到其他模式。

0
0 Comments

我在这里看到几个选项:

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

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

  3. 创建一个属性模型。一个属性belongs_to :parent_object,polymorphic: true具有一个key和一个value字段。采用这种方法,你可能会有一个基本的Business模型,每个业务可以has_many :attributes。商业的某些(非关系)属性(allows_smoking)是一个Attribute记录。一个Attribute的键可以是一个字符串,也可以是你有Ruby常量的数字。你实际上是在使用Attribute实体来创建选项#2的SQL版本。这可能是一个不错的选择,我自己在User或Profile模型中使用过这个方法。(尽管这种方法可能会产生一些性能损失)。

我真的很担心对于听起来像子类的东西,会有那么多(独立)模型,你可能能够通过使用关注点(在Rails 4中的一种语法糖,看一个关于关注点的神奇SO答案)来DRY共同的行为/方法。当然,你仍然有你的(最初的)迁移问题。

0