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
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.
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.
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.
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?
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.