Rails STI - 防止基类实例化

时间:2010-05-17 15:31:49

标签: ruby-on-rails

在基类实例化时,Rails STI情况有没有办法抛出错误?覆盖初始化将会执行此操作,但随后会逐渐减少到子类。

由于

6 个答案:

答案 0 :(得分:56)

John Topley的答案实际上是错误的。在基类中设置abstract_class = true实际上会导致子类自动停止设置其类型。另外,除非你在基类中使用set_table_name,否则子类会抱怨它们的表不存在。

这是因为abstract_class = true的目的是在不使用STI时设置继承,并希望在ActiveRecord :: Base和类之间的类层次结构中有一个抽象类(不由db表支持的类)一个或多个模型类。

初始化加注是一种解决方案,同时将validates_presence_of:type添加到基类是一种解决方案。

注意如果你要覆盖初始化,你需要调用super:

def initialize(*args)
  raise "Cannot directly instantiate an AbstractUser" if self.class == AbstractUser
  super
end

答案 1 :(得分:4)

你可以试试这个:

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

希望有所帮助

答案 2 :(得分:1)

我经常更喜欢简单地将new类方法设为私有:

class Base
  private_class_method :new 
end

这种方式意外实例化Base类会触发错误,但仍然可以使用Base.send(:new)对其进行实例化,以便为Base类编写测试。

答案 3 :(得分:0)

比验证存在性更好的是针对已知的可接受的非抽象类类型列表进行验证

  validates :type, :inclusion=> { :in => ["A", "B", "C"] }

因为仅验证存在性,“邪恶的开发人员”仍可以传入抽象类名称作为类型参数。

答案 4 :(得分:-1)

在initialize函数中检查该类是否是STI基类。

虽然问题是你为什么要这么做?尝试不同的设计似乎更有可能对您有所帮助。

答案 5 :(得分:-4)

您可以在基类中执行self.abstract_class = true告诉ActiveRecord它是一个抽象类。