有多少课程太多了?Rails STI

Ala*_*ody 5 ruby inheritance ruby-on-rails single-table-inheritance sti

我正在研究一个非常大的Rails应用程序.我们最初并没有使用太多的继承,但是我们从顾问那里获得了一些开眼界的经验,并且正在寻求重构我们的一些模型.

我们的应用程序中有很多以下模式:

class Project < ActiveRecord::Base
  has_many :graph_settings
end

class GraphType < ActiveRecord::Base
  has_many :graph_settings
  #graph type specific settings (units, labels, etc) stored in DB and very infrequently updated.
end

class GraphSetting < ActiveRecord::Base
  belongs_to :graph_type
  belongs_to :project
  # Project implementation of graph type specific settings (y_min, y_max) also stored in db.
end
Run Code Online (Sandbox Code Playgroud)

这也导致视图,帮助器和GraphSetting模型本身中的大量条件.这些都不好.

一个简单的重构,我们摆脱GraphType,支持使用更像这样的结构:

class Graph < ActiveRecord::Base
  belongs_to :project
  # Generic methods and settings
end

class SpecificGraph < Graph
  # Default methods and settings hard coded
  # Project implementation specific details stored in db.
end
Run Code Online (Sandbox Code Playgroud)

现在这对我来说非常有意义,简化测试,删除条件,并使以后的国际化更容易.但是我们只有15到30个图表.

我们有一个非常相似的模型(以复杂的方式作为例子),接近可能有100种不同的"类型",并且可能会加倍.他们都会拥有他们继承的关系和方法,有些人需要覆盖更多的方法,然后是其他方法.它似乎是完美的用途,但很多只是看起来很多.

很多是200个STI课程吗?我们应该看看另一种模式吗?

感谢任何智慧,我会回答任何问题.

And*_*Vit 4

如果差异仅在于班级的行为,那么我认为这应该不是问题,并且这是 STI 的良好候选者。(请注意,我从未尝试过使用如此多的子类。)

但是,如果您的 200 个 STI 类每个都有一些独特的属性,那么您将需要在主表中添加大量额外的数据库列,这些列在 99.5% 的情况下将为 NULL。这可能非常低效。

为了创建类似“多表继承”的东西,我之前成功所做的就是使用一些元编程来关联其他表以获取每个类特有的详细信息:

class SpecificGraph < Graph
  include SpecificGraphDetail::MTI
end

class SpecificGraphDetail < ActiveRecord::Base
  module MTI
    def self.included(base)
      base.class_eval do
        has_one :specific_graph_detail, :foreign_key => 'graph_id', :dependent => :destroy
        delegate :extra_column, :extra_column=, :to => :specific_graph_detail
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

委托意味着您可以访问关联的详细信息字段,就好像它们直接在模型上一样,而不是通过关联specific_graph_detail,并且出于所有意图和目的,它“看起来”就像这些只是额外的列。

您必须权衡需要连接这些额外详细信息表的情况与仅在主表中包含额外列的情况。这将决定是使用 STI 还是使用关联表的解决方案,例如我上面的解决方案。