Rails STI - 防止基类实例化
Posted
技术标签:
【中文标题】Rails STI - 防止基类实例化【英文标题】:Rails STI - Prevent base class from instantiation 【发布时间】:2010-05-17 15:31:49 【问题描述】:在 Rails STI 情况下,当基类被实例化时,有什么方法可以引发错误?覆盖初始化会做到这一点,但随后会渗透到子类。
谢谢
【问题讨论】:
【参考方案1】:John Topley 的回答实际上是错误的。在基类中设置 abstract_class= true 实际上会导致子类停止自动设置它们的类型。另外,除非你在基类中设置_table_name,否则子类会抱怨他们的表不存在。
这是因为 abstract_class=true 的目的是在您不使用 STI 并希望在 ActiveRecord::Base 和一个或多个模型类。
初始化 raise 是一种解决方案,将 validates_presence_of :type 添加到基类也是一种解决方案。
注意如果你重写了初始化,你需要调用 super:
def initialize(*args)
raise "Cannot directly instantiate an AbstractUser" if self.class == AbstractUser
super
end
【讨论】:
【参考方案2】:你可以试试这个:
class BaseClass
def initialize
raise "BaseClass cannot be initialized" if self.class == BaseClass
end
end
class ChildClass
end
结果将是:
a = BaseClass.new # Runtime Error
b = ChildClass.new # Ok
希望有帮助
【讨论】:
由于 BaseClass 可能会从 ActiveRecord::Base 继承,所以 initialize 可能应该调用 super。【参考方案3】:我通常更喜欢简单地将 new
类方法设为私有:
class Base
private_class_method :new
end
这种方式意外实例化 Base 类会触发错误,但仍然可以使用 Base.send(:new)
实例化它来为 Base 类编写测试。
【讨论】:
【参考方案4】:比验证存在性更好的是根据已接受的非抽象类类型的已知列表进行验证
validates :type, :inclusion=> :in => ["A", "B", "C"]
因为如果您只是为了存在而进行验证,“邪恶的开发者”仍然可以将抽象类名作为类型参数传递。
【讨论】:
【参考方案5】:在初始化函数中检查该类是 STI 基类。
虽然问题是您为什么要这样做?尝试不同的设计似乎更有可能对您有更多帮助。
【讨论】:
【参考方案6】:您可以在基类中使用self.abstract_class = true
告诉 ActiveRecord 它是一个抽象类。
【讨论】:
以上是关于Rails STI - 防止基类实例化的主要内容,如果未能解决你的问题,请参考以下文章