Reputation: 2531
I have two levels of inheritance with some of my models: (this is all in /app/models
)
A.rb
/A/B1.rb
/A/B1/C1.rb
/A/B1/C2.rb
/A/B1/C3.rb
/A/B2.rb
/A/B2/C1.rb
/A/B2/C2.rb
/A/B2/C3.rb
...
A.rb is a simple:
class A
def self.inherited(subclass)
puts "New subclass: #{subclass}"
end
# some methods
end
B1.rb is:
class A::B1 < A
# some methods
end
C1.rb is:
class A::B1::C1 < A::B1
# some methods
end
You can interpolate what the rest of the models look like.
When I load rails console
, I see this:
New subclass: A::B1
New subclass: A::B1::C1
New subclass: A::B2
Notice that A::B1::C2, A::B1::C3, and none of the A::B2 subclasses are inherited! Why is that?
It gets even weirder. In rails console
, I can then do this:
irb(main)> A::B1::C2
New subclass: A::B1::C2
A::B1::C2 < A::B1
irb(main)> A::B2::C1
New subclass: A::B2::C1
A::B2::C1 < A::B2
So I can type all the subclasses that weren't inherited, and then suddenly it fires the puts
message. I think this proves the issue is with the autoloader, rather than my code.
This is happening in my development environment with Ruby 1.9. and Rails 3.2.
Here are my config.autoload_paths
statements:
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Thanks in advance!
Upvotes: 4
Views: 972
Reputation: 183
This may be too late to help you, but I ran into the same issue, so hopefully this answer will help others.
If you are using the Spring
gem, your application is actually running in the background. So simply restarting won't re-run the initializers, and won't add those directories to your autoload path.
You want to run bin/spring stop
so that when you restart your app the initializers are run.
Upvotes: 0
Reputation: 2531
I wish I had a better answer but to Sergio's point, my subclasses are never directly mentioned so they aren't autoloaded.
I literally had to just write them out at the top of my class file:
B1.rb:
class A1::B1
A1::B1::C1 # simply mentioning the class autoloads it
A1::B2::C2
...
def foo
...
end
end
Upvotes: 0
Reputation: 76774
You'll need to include the various models in your config.autoload_paths
option:
#config/application.rb
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
This makes use of globbing - basically adding any files within a particular directory to your path. We use the above code for single-level directories (app/models/directory/1.rb
); if you wanted to use multiple levels, you'll have to indicate them like this:
Dir[Rails.root.join('app', 'models', '{*}', '{**}')]
Upvotes: 1