【问题标题】:Ruby on Rails - Alternatives to STI?Ruby on Rails - STI 的替代品?
【发布时间】:2013-07-04 03:40:47
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    我在这里看到了一些选项:

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

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

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

    我真的很担心有这么多(独立的)模型来处理听起来像子类的东西。有可能你可以通过使用 Concerns 来干掉常见的行为/方法(mixin 概念上的语法糖,请参阅awesome SO answer on concerns in Rails 4)。当然,您仍然有(最初的)迁移问题。

    【讨论】:

      【解决方案2】:

      在此处添加另一个选项:Serialized LOB (272)。 ActiveRecord 允许您使用serialize 对对象执行此操作:

      类用户

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-05
        • 2011-11-05
        • 1970-01-01
        • 1970-01-01
        • 2011-08-02
        • 1970-01-01
        • 2015-08-08
        相关资源
        最近更新 更多