5

I have a model object which subclasses ActiveRecord. Additionally, using STI, I have defined subclasses of this object, which define different types and behaviors. The structure looks something like this:

class AppModule < ActiveRecord::Base
  belongs_to :app 
end

class AppModuleList < AppModule

end

class AppModuleSearch < AppModule

end

class AppModuleThumbs < AppModule

end

Now, in a view where the user has the option to create new AppModules, I would like them to select from a dropdown menu. However I have not been able to get a list of subclasses of AppModule using the subclasses() method:

<% form_for(@app_module) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :type %><br />
    <%= f.select(:type, options_from_collection_for_select(@app_module.subclasses().map{ |c| c.to_s }.sort)) %>
  </p>
  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

I get:

NoMethodError: undefined method `subclasses' for #<AppModule:0x1036b76d8>

I'd appreciate any help. Thanks a lot!

joschi
  • 12,746
  • 4
  • 44
  • 50
Engin Kurutepe
  • 6,719
  • 3
  • 34
  • 64
  • Which version of Ruby on Rails are you using? – outis Nov 14 '10 at 11:43
  • Class has a `descendents` method in [3.0.0](http://rubydoc.info/docs/rails/3.0.0/Class#descendants-instance_method), but not [2.3.8](http://rubydoc.info/docs/rails/2.3.8/Class#descendants-instance_method). – outis Nov 14 '10 at 12:21

2 Answers2

10

It looks as though subclasses and the like is a recent addition (the method exists on various classes at various points in time, but kept getting shuffled around and removed; that link seems to be the earliest point that the method stuck around). If upgrading to the most recent version of RoR isn't an option, you can write your own subclasses and populate it using Class#inherited (which is what RoR's descendents_tracker does).

outis
  • 75,655
  • 22
  • 151
  • 221
  • 3
    For anyone directed here by Google, if your classes are lazy loaded, DescendantsTracker won't know about them until they are used. – Alan Lattimore Feb 24 '17 at 19:15
5

AppModule.descendants.map &:name is what you're looking for. As in:

<% form_for(@app_module) do |f| %>
  <%= f.error_messages %>

  <p>
    <%= f.label :type %><br />
    <%= f.select(:type, options_from_collection_for_select(AppModule.descendants.map(&:name).sort)) %>
  </p>
  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %> 
Mike
  • 9,692
  • 6
  • 44
  • 61