polishing ruby by ryan davis

STI and Abstract Classes Driving You Nuts?

Published 2007-01-05 @ 15:16

If you happen to be hit by Ticket #5704: Bug in ActiveRecord::Base when mixing STI and abstract models, and you’re seeing failures to find STI instances intermittently in development mode, try the following:

class MyAbstractModel < ActiveRecard::Base
  self.abstract_class = false
  # ...
end

-----
  
class MySTIModel < MyAbstractModel
  TYPES = %w(Sub1 Sub2 Sub3)
  def self.inherited(cls)
    super
    raise "not in #{self.class}::TYPES: #{cls}" unless TYPES.include? cls.name
  end
end
    
MySTIModel::TYPES.each do |f|
  require_dependency f.underscore
end

-----

class Sub1 < MySTIModel; end
class Sub2 < MySTIModel; end
class Sub3 < MySTIModel; end

It is a stupid bug and I can’t do much about it, but the above workaround seems to be a nice tradeoff between horrible hack and maintainability. By pushing the list of subclasses up to the TYPES array, you keep it visible and near the top of the file. By having the inherited hook, you keep slipups in maintainability as visible as possible.

UPDATED: All of the classes in my actual use were single word classes. Kevin Clark pointed out that my code doesn’t work with camel-cased/multiple-word class names. The code above has been updated to fix that.