有多少课程太多了? Rails STI

时间:2010-09-09 15:14:38

标签: ruby-on-rails ruby inheritance 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

这也会导致视图,帮助器和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

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

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

200个STI课程对很多人来说?我们应该看看另一种模式吗?

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

1 个答案:

答案 0 :(得分:4)

如果差异只是在类的行为中,那么我认为它应该不是问题,这是STI的一个很好的候选者。 (请注意,我从未尝试过这么多子类。)

但是,如果你的200个STI类都有一些独特的属性,那么你需要在master表中有很多额外的数据库列,这些列在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

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

您必须权衡需要加入这些额外详细信息表的情况,而不是在主表中添加额外的列。这将决定是使用STI还是使用关联表的解决方案,例如上面的解决方案。