# Find every subclass of an object

**URL:** <https://www.ruby-forum.com/t/find-every-subclass-of-an-object/148553>\
**Category:** Rails\
**Created:** [September 14, 2008, 10:17pm UTC](https://www.ruby-forum.com/t/find-every-subclass-of-an-object/148553 "2008-09-14T22:17:33Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![DyingToLearn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3d9bf3/32.png) [@DyingToLearn](https://www.ruby-forum.com/u/DyingToLearn)\
**Post date:** [September 14, 2008, 10:17pm UTC](https://www.ruby-forum.com/t/find-every-subclass-of-an-object/148553/1 "2008-09-14T22:17:33Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![DyingToLearn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3d9bf3/32.png) [@DyingToLearn](https://www.ruby-forum.com/u/DyingToLearn)\
**Post date:** [September 14, 2008, 10:28pm UTC](https://www.ruby-forum.com/t/find-every-subclass-of-an-object/148553/2 "2008-09-14T22:28:07Z")

</div>

On 14 Sep 2008, at 21:05, DyingToLearn wrote:

> 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

---

<div class="post-metadata">

**Author:** ![DyingToLearn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/3d9bf3/32.png) [@DyingToLearn](https://www.ruby-forum.com/u/DyingToLearn)\
**Post date:** [September 15, 2008, 4:08am UTC](https://www.ruby-forum.com/t/find-every-subclass-of-an-object/148553/3 "2008-09-15T04:08:20Z")

</div>

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 🙂

Paul
