Edge Rails not loading constants in base classes?

I'm wondering if I've hit an edge rails bug. I'm using single table
inheritance to map different types of components for a management app.
The inheritance works fine, have the "type" column set, etc.

The issue I'm hitting is that subclasses don't appear to be
auto-loading missing constants (ie ServiceType to service_type.rb).
This snippet will show the issue:

   ## component_type.rb (single-table inheritance)
   # if I uncomment these requires, it works:
   #require 'service_type'
   #require 'config_file'
   class ComponentType < ActiveRecord::Base
      def self.load_config_files(service_hint)
        service_type = ServiceType.find_by_service_type(service_hint)
        ConfigFile.find(:all)
      end
   end

   ## component_type/medius.rb
   class ComponentType::Medius < ComponentType
   end

Then, my controller does this:

    component_type, service_hint = LoaderRule.detect(basename)
    component_type.class.load_config_files(service_hint)

I can get it to work by simply uncommenting the require statements. The
specific error is:

uninitialized constant ServiceType

vendor/rails/activesupport/lib/active_support/dependencies.rb:263:in
`load_missing_constant'
vendor/rails/activesupport/lib/active_support/dependencies.rb:446:in
`const_missing'
vendor/rails/activesupport/lib/active_support/dependencies.rb:458:in
`const_missing'
app/models/component_type.rb:29:in `load_config_files'
app/models/component_type.rb:17:in `load_bundle'
app/models/component_type.rb:14:in `load_bundle'
app/models/loader.rb:69:in `load_file'
app/controllers/loader_controller.rb:4:in `test'

Nate,

Where is service_type.rb located? Also, do you override/add additional
load paths in your environment.rb? I'm wondering if the load path for
that file is present in $LOAD_PATH, but not Dependencies.load_paths.

-Aaron

Nate Wiger wrote:

Hi Aaron,

The file is in the same directory, in the standard path of app/models:

[nwiger@sceapdsd-172-31-30-84:models]$ ls -lF
total 144K
drwxr-xr-x 3 nwiger sysadm 4.0K Nov 16 11:56 component_type/
-rw-r--r-- 1 nwiger sysadm 1.8K Nov 16 12:19 component_type.rb
-rw-r--r-- 1 nwiger sysadm 92 Nov 15 16:43 service_type.rb

[nwiger@sceapdsd-172-31-30-84:models]$ ls -lF component_type/
total 12K
-rw-r--r-- 1 nwiger sysadm 161 Nov 16 11:56 medius.rb
-rw-r--r-- 1 nwiger sysadm 333 Nov 15 15:22 svo.rb

I don't actually mess with LOAD_PATH at all, I'm just using the
standard app/models and app/controllers paths.

I tried experimenting some more, even flattening the structure to
eliminate the subdir (and hence a level of ::'s). However, this did not
affect it at all. It appears that a subclass does not get any
superclass's constants loaded.

I think the problem is this section in const_missing in:
   vendor/rails/activesupport/lib/active_support/dependencies.rb:466

      rescue NameError => e
        # Make sure that the name we are missing is the one that caused
the error
        parent_qualified_name = Dependencies.qualified_name_for parent,
class_id
        raise unless e.missing_name? parent_qualified_name
        qualified_name = Dependencies.qualified_name_for self, class_id
        raise NameError.new("uninitialized constant
#{qualified_name}").copy_blame!(e)
      end

It appears that for subclasses, this does not properly identify the
constant as being the correct one, since the base class name does not
match.

Any ideas how to fix this properly?

It appears that for subclasses, this does not properly identify the
constant as being the correct one, since the base class name does not
match.

Any ideas how to fix this properly?

Can you create a failing test case? That'll help us isloate it a bit better.

Hi~

I'm wondering if I've hit an edge rails bug. I'm using single table
inheritance to map different types of components for a management app.
The inheritance works fine, have the "type" column set, etc.

The issue I'm hitting is that subclasses don't appear to be
auto-loading missing constants (ie ServiceType to service_type.rb).
This snippet will show the issue:

   ## component_type.rb (single-table inheritance)
   # if I uncomment these requires, it works:
   #require 'service_type'
   #require 'config_file'
   class ComponentType < ActiveRecord::Base

Here you make an AR class ComponentType.

      def self.load_config_files(service_hint)
        service_type = ServiceType.find_by_service_type(service_hint)
        ConfigFile.find(:all)
      end
   end

   ## component_type/medius.rb
   class ComponentType::Medius < ComponentType
   end

Here you are making a Medius class within a ComponentType class not a class within a module like you might be thinking.

[nwiger@sceapdsd-172-31-30-84:models]$ ls -lF
total 144K
drwxr-xr-x 3 nwiger sysadm 4.0K Nov 16 11:56 component_type/
-rw-r--r-- 1 nwiger sysadm 1.8K Nov 16 12:19 component_type.rb
-rw-r--r-- 1 nwiger sysadm 92 Nov 15 16:43 service_type.rb

Here you have a component_type directory and a component_type class. I think this is where your problem lies. If you either rename the component_type directory or the component_type class then I think it will resolve your conflict.

Cheers-
-- Ezra Zygmuntowicz-- Lead Rails Evangelist
-- ez@engineyard.com
-- Engine Yard, Serious Rails Hosting
-- (866) 518-YARD (9273)

Nesting classes should work fine (I use it). I suspected that nesting a subclass in its superclass (A::B < A) is giving the grief, but a manufactured test case passes.

Nate, could you set Dependencies.log_activity = true and include the ServiceType lookup error?

jeremy

Jeremy,

I tried setting Dependencies.log_activity = true, but I didn't get any
additional output. Where should this setting go? I tried both the class
file and the environment.rb

Ezra,

I tried flattening the namespace as one of my initial troubleshooting
techniques:

   # component_type_medius.rb
   class ComponentTypeMedius < ComponentType
   end

But it made no difference - the failure was the same error. (I
restarted the server to make sure it wasn't caching anything)

This is Resolved, it was not a Rails issue (directly).

In my class, I was operating a particular set of methods within a
Dir.chdir() block. This was causing dependencies.rb not to properly
resolve the const_missing path via search_for_file(), since it was in
/tmp/blah/blah.

I resolved this by finding a different way to accomplish the chdir()
magic.

Thanks for your quick and helpful responses.

-Nate