Find every subclass of an object

Hi,

I have this class:

class MoldItem < ActiveRecord::Base   self.abstract_class = true end

And then I have a (currenly unspecified) number of classes such as these:

class StringMoldItem < MoldItem end class LinkMoldItem < MoldItem end

I would like to add a class method to MoldItem that will return all of its subclasses. In the above example, this method would return the Array [StringMoldItem, LinkMoldItem].

I have been able to write this method in several ways that are successful using script/console. But as soon as I try to use the method within my browser (i.e. calling it in a controller) I get unexpected results.

Option 1:   def self.subklasses(direct = false)       #ensure files are loaded by rails       Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }

    classes =     if direct       ObjectSpace.each_object(Class) do |c|         next unless c.superclass == self         classes << c       end     else       ObjectSpace.each_object(Class) do |c|         next unless c.ancestors.include?(self) and (c != self)         classes << c       end     end     classes   end

Option 2:    def self.subklasses       Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }      @@subclasses[MoldItem]    end

Option 3:

   def self.inherited other      super if defined? super    ensure      ( @subclasses ||= ).push(other).uniq!    end

   def self.subklasses       Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }      @subclasses ||=      @subclasses.inject( ) do |list, subclass|        list.push(subclass, *subclass.subklasses)      end    end

Results: when I run MoldItem.subklasses using script/console, I get the correct result for all three options. When I run it from a controller (by visiting a page of my website), the first request after starting mongrel works. However, every subsequent request will return or nil (depending on the option).

I think the problem is a conflict between this line: Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file } (which is meant to ensure that the subclasses such as StringMoldItem and LinkMoldItem exist) and rails' fancy way of requiring source files (would that be ActiveSupport::Dependencies#load_missing_constant?).

Do you have any suggestions for how I can dynamically return a list of the subclasses of MoldItem?

I think the problem is a conflict between this line: Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file } (which is meant to ensure that the subclasses such as StringMoldItem and LinkMoldItem exist) and rails' fancy way of requiring source files (would that be ActiveSupport::Dependencies#load_missing_constant?).

Probably. Using require_dependency instead require might help.

Fred

Thanks!

I just needed to change this: Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }

to this: Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require_dependency file }

Now I just need to think of some way to not require reading the entire directory contents every time the method is called :slight_smile:

Paul

Frederick Cheung wrote: