【问题标题】:Rails STI - Prevent base class from instantiationRails STI - 防止基类实例化
【发布时间】:2010-05-17 15:31:49
【问题描述】:

在 Rails STI 情况下,当基类被实例化时,有什么方法可以引发错误?覆盖初始化会做到这一点,但随后会渗透到子类。

谢谢

【问题讨论】:

    标签: ruby-on-rails


    【解决方案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 它是一个抽象类。

            【讨论】:

              猜你喜欢
              • 2021-05-11
              • 1970-01-01
              • 2015-06-09
              • 2017-10-30
              • 2023-03-07
              • 1970-01-01
              • 2015-04-02
              • 2011-12-20
              • 1970-01-01
              相关资源
              最近更新 更多