Reputation: 7229
I have two classes in rails 3.2.6:
self.table_name
to bar_foos
)When I go into console, I get:
> Bar::Foo
=> Bar::Foo(id: ...)
> Foo # or ::Foo
LoadError: expected models/bar/foo.rb to define Foo
What's wrong?
Upvotes: 4
Views: 1011
Reputation: 7229
Turns out that this line in config/applications.rb was the problem:
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
With explicitly set autoload, Rails got confused; rather than look under models/ by namespacing appropriately, it looked at the first autoload file it had (which was, mistakenly, models/bar/foo.rb) and found (true) that it failed to define Foo (it defines Bar::Foo).
So evidently Rails 3 already knows to look in models/ subdirs for namespaced models.
Thanks to Antiarc on freenode #RubyOnRails for helping figure this out.
Upvotes: 2
Reputation: 62698
We solved this in IRC, but the core issue is that there was a config.autoload_paths
glob set that was including models/**
as load paths.
Rails' auto-loader iterates the load paths, and tacks on the constant name. Once it finds a file that exists, it tries to load it, then throws an exception if the constant is not available.
So, what was happening is Rails had a list of load paths like:
/models/bar/
/models/
It was iterating the paths, and would find a match at /models/bar/foo.rb
, which it then loads (which makes Bar::Foo
available, but not Foo
), then throws the exception because Foo
isn't available.
The solution in this case was to remove the autoload_paths
setting, so that Rails would not find the wrong file to load for the root-level constant.
Upvotes: 5