Does Rails Define Modules For Me?

In
an earlier post,
I talked about how we define namespaced classes in Rails.

That is, should we use this form?

Nested Class Definition

moduleMyModule

classMyClass

# ...

end

end

or this one?

Shorthand Class Definition

classMyModule::MyClass

# ...

end

As I was researching that post, I was trying to understand where the
namespaces were coming from when using the shorthand form of class
MyModule::MyClass. There was no declaration of MyModule as a
module or class in any of my code. I also know that, in plain Ruby, I
can’t define a class that way without first defining MyModule.
If I try, I’ll get a NameError.

So how was my code loading into Rails without blowing up?

I searched Google with a query that matches the title of this post and
didn’t find an answer, so I decided to research it and write the
answer myself.

If MyModule is already defined as a class or namespace, the
autoloader never comes into play. But if it isn’t defined, the
autoloader tries to find and load a definition for me.

The Rails autoloader lives in ActiveSupport::Dependencies. Its
workhorse method is load_missing_constant, which is called from a
const_missing handler that the autoloader injects into Module.

load_missing_constant looks for a file that might define the
constant (MyModule in this example). If it can’t find one,
it uses autoload_module! to dynamically define MyModule as a
module as long as autoloadable_module? agrees.

autoloadable_module? returns true if the potential module name
matches a directory name somewhere in one of my configured autoload
directories.

If there is no such directory, then the autoloader tries a few other
things. If none of them work, it will ultimately raise the same
NameError we get from stock Ruby.

So, if I have a directory like app/models/my_module/ or
app/controllers/my_module in my application, then
autoloadable_module? will return true and autoload_module! will
dynamically define MyModule as a module. If not, I’ll get an error.