如何设计结构以便我能够获得STI的所有好处而没有任何后果?(我知道这样做相当不负责任。)

13 浏览
0 Comments

如何设计结构以便我能够获得STI的所有好处而没有任何后果?(我知道这样做相当不负责任。)

假设我有一个Rails应用中的关联示例:

enter image description here

我正在考虑将 *Posting 模型合并为STI。STI的一个问题是可能会有许多仅与一个子类相关的属性(即,许多非规范化的nil值)。当你的子类在未来发展壮大时,这一点尤为令人担忧。我阅读了一些相关的帖子(例如这个),然而,正如你在我的示例中所看到的,潜在的特定于子类的字段不一定只是属性,而是很多belongs_to关联。

我的问题是,我如何重新构建这个结构,以便从一个Posting模型中使用STI来处理所有共同的属性/方法(在我的实际应用中将有相当多的这些),但是避免让独特的子类特定属性和belongs_to关联在Posting模型中堆积?另外,能够访问@board.postings并使用那些标准方法是很重要的。

例如,我考虑将特定于类型的属性移到另一个模型中:

class CarPosting < Posting
  has_one: car_posting_detail
end
class CarPostingDetail < ActiveRecord::Base
  belongs_to :car_posting
  belongs_to :car_make
  belongs_to :car_model
end

虽然这开始创建了很多连接,但我不确定我是否正确地声明了has_one/belongs_to,并且你必须开始链式调用(例如,@posting.car_posting_detail.car_make)。

你见过其他实现这一点的设计模式吗?

0
0 Comments

STI是Rails中的一种设计模式,用于实现对象的继承关系。然而,使用STI可能会导致一些问题和限制。问题是如何在不受STI限制的情况下享受所有的好处。为了解决这个问题,可以使用多态关联。

多态关联是一种在Rails中实现多态关系的方法。它允许一个模型通过一个关联可以指向多个不同模型的实例。在这种情况下,可以使用多态关联来实现类似STI的效果,同时避免STI的限制。

首先,在Post模型中添加一个多态关联声明:

Post model belongs_to :postable, :polymorphic => true

然后,在所有需要被关联的类(如car、event等)中添加相同的关联声明:

has_many :posts, as: :postable 

在Post模型中,postable_id和postable_type字段将保存关联对象的信息。这样,就可以通过Post模型来访问不同类型的对象。

更多关于多态关联的信息可以在这里找到:

http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

使用多态关联可以实现类似STI的效果,同时避免了STI的一些限制。在上面的对话中,还提到了如何使用多态关联来实现和实现细节的讨论。

0
0 Comments

如何结构化以便在不产生任何后果的情况下获得STI的所有好处?(我知道这样做很不负责任。)

你基本上有两种选择来实现继承。

首先,你可以像你建议的那样使用Rails的STI。缺点是对于不使用所有字段的子类,你会得到一个空属性。你通过为另一个模型添加类型特定的属性来减少这个问题的想法是减少这个问题的好方法。然而,你应该尽可能地保持实现的DRY,通过为Posting定义has_one :detail。然后你可以简单地在Posting的子类中分配特定的detail类型。例如,CarPosting的detail将是CarPostingDetail。这很方便,因为那么所有的Posting子类都将以相同的方式访问它们的细节,但仍然具有不同的细节。所以查询现在看起来像.detail.car_make。为了进一步,你可以在你的Posting模型中定义一个自定义的辅助方法来获取当前Posting的每个属性,并为其创建一个访问器。现在整个细节层是透明的,你可以通过.car_make简单地访问这些属性。

其次,你可以使用一个抽象类。这本质上是STI的反向。你创建一个永远不能实例化的抽象模型类。因此,你不能在Posting类中定义任何关系,因为它没有表。抽象Posting类的每个子类都有自己单独的表。这样做的主要优点是可以为所有的Posting类型定义方法,而不需要将它们复制粘贴到每个模型中。因此,如果模型之间有一些重叠的功能,但数据重叠很少,这个选项更好。

抽象类本质上不就是一个concern吗?

正如Josh所提到的,我考虑过抽象类(或concern)。然而,这样做会不会让我失去我需要的.postings功能?(:board has_many :postings)

是的Josh,本质上来说,concern和抽象类可以实现相同的功能。我想唯一的区别是从面向对象的角度来看,抽象类允许你的模型成为某种类型,而不是扩展模型的功能。我认为抽象类和concern都会消除Board <=> Posting的关系。除非有一些巧妙的方法来操纵多态关联,使得每个Posting的子类都与Board有关系。

0