Ruby on Rails - STI的替代品?

时间:2013-07-06 02:12:35

标签: ruby-on-rails activerecord

我有许多不同的模型(接近20个),它们有一些共同的属性,但在某些程度上也有所不同。 STI起初看起来很有吸引力,但我不知道随着产品的快速发展,各种模型会如何随着时间的推移而发展。

与我们的应用程序很好地平行的是Yelp。 Yelp如何在Rails中管理一些东西?所有帖子都有一些共同的属性,如“地址”。然而,他们在其他方面存在很大差异。例如,您有餐馆的预订选项,而其他人可能没有。餐馆还有许多其他属性,如“允许饮酒”,不适用于他人。使用STI执行此操作将很快失控。

那么下一个最佳选择是什么?与Postgres的HStore?我不习惯使用HStore来做任何事情。 HStore解决了一些问题,同时介绍了其他问题,比如缺乏数据类型,缺乏参照完整性检查等等。我希望有一个可靠的关系数据库作为构建的基础。所以在Yelp案例中,可能是餐馆模特是我要去的地方。我已经看过像这里的建议 - http://mediumexposure.com/multiple-table-inheritance-active-record/,但是我很乐意做很多猴子修补以获得如此普遍的东西。

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

我是否忽略了一些可能导致大量问题的关键问题?

2 个答案:

答案 0 :(得分:6)

我在这里看到几个选项:

  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: truekey字段的属性value。使用此方法,您可能拥有基本Business模型,每个商家都可以has_many :attributes。业务的某些(非关系?)属性(allows_smoking)是一个Attribute记录。 Attribute的键可以是字符串,也可以是Ruby常量的数字。您实际上是使用Attribute实体来创建选项#2的SQL版本。这可能是一个不错的选择,我自己也将它用于User或Profile模型。 (虽然使用这种方法可以了解一些性能指标)。

  4. 我真的担心拥有那些听起来像子类的东西的那些(独立)模型。通过使用Concerns(关于mixin概念的语法糖,参见awesome SO answer on concerns in Rails 4),你可能能够干掉常见的行为/方法。当然,你仍然有(初始)迁移问题。

答案 1 :(得分:1)

在此处添加其他选项:Serialized LOB(272)。 ActiveRecord允许您使用serialize

对对象执行此操作

class User<的ActiveRecord :: Base的   序列化:首选项 端

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

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

要理解的重要结果是存储在序列化LOB中的属性将不可索引,并且当然不能以任何高效的方式进行搜索。如果你后来发现一个列需要作为索引可用,你必须编写[最有可能]一个Ruby程序来执行转换(虽然默认序列化在Yaml中,所以任何Yaml解析器就足够了。)

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