我正在处理一个非常大的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
这还会在 View ,助手和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类吗?还有其他模式值得我们注意吗?
感谢您的智慧,我将回答任何问题。
最佳答案
如果差异仅在于类的行为,那么我认为这不应该是问题,这是STI的不错选择。 (请记住,我从未尝试过这么多子类。)
但是,如果您的200个STI类每个都有一些唯一的属性,则在主表中将需要很多额外的数据库列,这些列将为NULL(99.5%的时间)。这可能是非常低效的。
为了创建类似“多表继承”的东西,我成功完成的工作是使用一些元编程来将其他表关联为每个类唯一的细节:
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还是使用关联表的解决方案,例如我上面的解决方案。
关于ruby-on-rails - 多少类太多? Rails STI,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3677924/