开发者

Rails STI - Prevent base class from instantiation

Is there any way in a Rails STI situation to throw an error when the base class is Instantiated? Overriding initialize will do i开发者_Go百科t but then that gets trickled down to the subclasses.

Thanks


The answer by John Topley is actually wrong. Setting abstract_class = true in the base class will actually cause the child classes to stop setting their type automatically. Plus, unless you set_table_name in the base class, the child classes will complain their table does not exist.

This is because the purpose of abstract_class=true is to set up inheritance when you are NOT using STI, and want to have an abstract class (class not backed by a db table) in your class hierarchy between ActiveRecord::Base and one or more model classes.

Having initialize raise is one solution, also adding validates_presence_of :type to the base class is a solution.

Note if you DO override initialize, you need to call super:

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


You can try this:

class BaseClass
  def initialize
    raise "BaseClass cannot be initialized" if self.class == BaseClass
  end
end

class ChildClass
end

the result will be:

a = BaseClass.new  # Runtime Error
b = ChildClass.new # Ok

Hope that helps


I often prefer to simply make the new class method private with:

class Base
  private_class_method :new 
end

This way accidental instantiation of the Base class triggers an error, but it's still possible to instantiate it with Base.send(:new) to write tests for the Base class.


even better than validating the presence is validating against the known list of accepted non abstract class types

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

because if you validate just for presence an "evil developer" can still pass in the abstract class name as the type parameter.


In the initialize function check that the class is the STI base class.

Though the question is why would you exactly want to do this? It seems more likely that trying out a different design might help you more.


You can do self.abstract_class = true in the base class to tell ActiveRecord that it's an abstract class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜