2014-12-14 18:57:17 -05:00
|
|
|
|
Constant Autoloading and Reloading
|
|
|
|
|
==================================
|
|
|
|
|
|
|
|
|
|
This guide documents how constant autoloading and reloading works.
|
|
|
|
|
|
|
|
|
|
After reading this guide, you will know:
|
|
|
|
|
|
|
|
|
|
* Key aspects of Ruby constants
|
|
|
|
|
|
2014-12-16 03:43:15 -05:00
|
|
|
|
* The purpose of `autoload_paths`
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
* How constant autoloading works
|
|
|
|
|
|
|
|
|
|
* What is `require_dependency`
|
|
|
|
|
|
|
|
|
|
* How constant reloading works
|
|
|
|
|
|
|
|
|
|
* Solutions to common autoloading gotchas
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Introduction
|
|
|
|
|
------------
|
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
Ruby on Rails allows applications to be written as if their code was preloaded.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
In a normal Ruby program a class needs to load its dependencies:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
require 'application_controller'
|
|
|
|
|
require 'post'
|
|
|
|
|
|
|
|
|
|
class PostsController < ApplicationController
|
|
|
|
|
def index
|
|
|
|
|
@posts = Post.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Our Rubyist instinct quickly sees some redundancy in there: If classes were
|
2014-12-15 10:41:23 -05:00
|
|
|
|
defined in files matching their name, couldn't their loading be automated
|
2014-12-14 18:57:17 -05:00
|
|
|
|
somehow? We could save scanning the file for dependencies, which is brittle.
|
|
|
|
|
|
|
|
|
|
Moreover, `Kernel#require` loads files once, but development is much more smooth
|
|
|
|
|
if code gets refreshed when it changes without restarting the server. It would
|
|
|
|
|
be nice to be able to use `Kernel#load` in development, and `Kernel#require` in
|
|
|
|
|
production.
|
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
Indeed, those features are provided by Ruby on Rails, where we just write
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class PostsController < ApplicationController
|
|
|
|
|
def index
|
|
|
|
|
@posts = Post.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This guide documents how that works.
|
|
|
|
|
|
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
Constants Refresher
|
|
|
|
|
-------------------
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
While constants are trivial in most programming languages, they are a rich
|
|
|
|
|
topic in Ruby.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
It is beyond the scope of this guide to document Ruby constants, but we are
|
|
|
|
|
nevertheless going to highlight a few key topics. Truly grasping the following
|
|
|
|
|
sections is instrumental to understanding constant autoloading and reloading.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
### Nesting
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
Class and module definitions can be nested to create namespaces:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
```ruby
|
|
|
|
|
module XML
|
|
|
|
|
class SAXParser
|
|
|
|
|
# (1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
The *nesting* at any given place is the collection of enclosing nested class and
|
|
|
|
|
module objects outwards. For example, in the previous example, the nesting at
|
|
|
|
|
(1) is
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
```ruby
|
|
|
|
|
[XML::SAXParser, XML]
|
|
|
|
|
```
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
It is important to understand that the nesting is composed of class and module
|
|
|
|
|
*objects*, it has nothing to do with the constants used to access them, and is
|
|
|
|
|
also unrelated to their names.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
For instance, while this definition is similar to the previous one:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
```ruby
|
|
|
|
|
class XML::SAXParser
|
|
|
|
|
# (2)
|
|
|
|
|
end
|
|
|
|
|
```
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
the nesting in (2) is different, `XML` does not belong to it:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
```ruby
|
|
|
|
|
[XML::SAXParser]
|
|
|
|
|
```
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
We can see in this example that the name of a class or module that belongs to a
|
2014-12-15 08:15:36 -05:00
|
|
|
|
certain nesting does not necessarily correlate with the namespaces at the spot.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
Even more, they are totally independent, take for instance
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
```ruby
|
|
|
|
|
module X::Y
|
|
|
|
|
module A::B
|
|
|
|
|
# (3)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
The nesting in (3) consists of two module objects:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
```ruby
|
|
|
|
|
[A::B, X::Y]
|
2014-12-14 18:57:17 -05:00
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
So, it not only doesn't end in `A`, which does not even belong to the nesting,
|
|
|
|
|
but it also contains `X::Y`, which is independent from `A::B`.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
The nesting is an internal stack maintained by the interpreter, and it gets
|
|
|
|
|
modified according to these rules:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
* The class object following a `class` keyword gets pushed when its body is
|
|
|
|
|
executed, and popped after it.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
* The module object following a `module` keyword gets pushed when its body is
|
|
|
|
|
executed, and popped after it.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 12:22:21 -05:00
|
|
|
|
* A singleton class opened with `class << object` gets pushed, and popped later.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
* When any of the `*_eval` family of methods is called using a string argument,
|
|
|
|
|
the singleton class of the receiver is pushed to the nesting of the eval'ed
|
|
|
|
|
code.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 12:22:21 -05:00
|
|
|
|
* The nesting at the top-level of code interpreted by `Kernel#load` is empty
|
|
|
|
|
unless the `load` call receives a true value as second argument, in which case
|
|
|
|
|
a newly created anonymous module is pushed by Ruby.
|
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
It is interesting to observe that blocks do not modify the stack. In particular
|
|
|
|
|
the blocks that may be passed to `Class.new` and `Module.new` do not get the
|
|
|
|
|
class or module being defined pushed to their nesting. That's one of the
|
2014-12-15 08:06:16 -05:00
|
|
|
|
differences between defining classes and modules in one way or another.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
The nesting at any given place can be inspected with `Module.nesting`.
|
|
|
|
|
|
2014-12-14 18:57:17 -05:00
|
|
|
|
### Class and Module Definitions are Constant Assignments
|
|
|
|
|
|
|
|
|
|
Let's suppose the following snippet creates a class (rather than reopening it):
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class C
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Ruby creates a constant `C` in `Object` and stores in that constant a class
|
|
|
|
|
object. The name of the class instance is "C", a string, named after the
|
|
|
|
|
constant.
|
|
|
|
|
|
|
|
|
|
That is,
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class Project < ActiveRecord::Base
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
performs a constant assignment equivalent to
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
Project = Class.new(ActiveRecord::Base)
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
Similarly, module creation using the `module` keyword as in
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
module Admin
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
performs a constant assignment equivalent to
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
Admin = Module.new
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
WARNING. The execution context of a block passed to `Class.new` or `Module.new`
|
|
|
|
|
is not entirely equivalent to the one of the body of the definitions using the
|
2014-12-15 10:41:23 -05:00
|
|
|
|
`class` and `module` keywords. But both idioms result in the same constant
|
|
|
|
|
assignment.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
Thus, when one informally says "the `String` class", that really means: the
|
|
|
|
|
class object the interpreter creates and stores in a constant called "String" in
|
|
|
|
|
the class object stored in the `Object` constant. `String` is otherwise an
|
|
|
|
|
ordinary Ruby constant and everything related to constants applies to it,
|
|
|
|
|
resolution algorithms, etc.
|
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
Likewise, in the controller
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class PostsController < ApplicationController
|
|
|
|
|
def index
|
|
|
|
|
@posts = Post.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`Post` is not syntax for a class. Rather, `Post` is a regular Ruby constant. If
|
|
|
|
|
all is good, the constant evaluates to an object that responds to `all`.
|
|
|
|
|
|
|
|
|
|
That is why we talk about *constant autoloading*, Rails has the ability to load
|
|
|
|
|
constants on the fly.
|
|
|
|
|
|
|
|
|
|
### Constants are Stored in Modules
|
|
|
|
|
|
|
|
|
|
Constants belong to modules in a very literal sense. Classes and modules have
|
2014-12-15 13:24:15 -05:00
|
|
|
|
a constant table; think of it as a hash table.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-16 03:16:58 -05:00
|
|
|
|
Let's analyze an example to really understand what that means. While in a
|
|
|
|
|
casual setting some abuses of language are customary, the exposition is going
|
|
|
|
|
to be exact here for didactic purposes.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-16 03:16:58 -05:00
|
|
|
|
Let's consider the following module definition:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
module Colors
|
|
|
|
|
RED = '0xff0000'
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
First, when the `module` keyword is processed the interpreter creates a new
|
|
|
|
|
entry in the constant table of the class object stored in the `Object` constant.
|
2014-12-15 03:40:41 -05:00
|
|
|
|
Said entry associates the name "Colors" to a newly created module object.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
Furthermore, the interpreter sets the name of the new module object to be the
|
|
|
|
|
string "Colors".
|
|
|
|
|
|
|
|
|
|
Later, when the body of the module definition is interpreted, a new entry is
|
|
|
|
|
created in the constant table of the module object stored in the `Colors`
|
2014-12-15 03:40:41 -05:00
|
|
|
|
constant. That entry maps the name "RED" to the string "0xff0000".
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
In particular, `Colors::RED` is totally unrelated to any other `RED` constant
|
|
|
|
|
that may live in any other class or module object. If there were any, they
|
|
|
|
|
would have separate entries in their respective constant tables.
|
|
|
|
|
|
|
|
|
|
Put special attention in the previous paragraphs to the distinction between
|
2014-12-15 10:39:34 -05:00
|
|
|
|
class and module objects, constant names, and value objects associated to them
|
2014-12-15 03:40:41 -05:00
|
|
|
|
in constant tables.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
### Resolution Algorithms
|
|
|
|
|
|
|
|
|
|
#### Resolution Algorithm for Relative Constants
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
2014-12-15 09:30:12 -05:00
|
|
|
|
At any given place in the code, let's define *cref* to be the first element of
|
2014-12-15 09:45:25 -05:00
|
|
|
|
the nesting if it is not empty, or `Object` otherwise.
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
2014-12-15 09:45:25 -05:00
|
|
|
|
Without getting too much into the details, the resolution algorithm for relative
|
|
|
|
|
constant references goes like this:
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
2014-12-15 09:45:25 -05:00
|
|
|
|
1. If the nesting is not empty the constant is looked up in its elements and in
|
|
|
|
|
order. The ancestors of those elements are ignored.
|
|
|
|
|
|
|
|
|
|
2. If not found, then the algorithm walks up the ancestor chain of the cref.
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
3. If not found, `const_missing` is invoked on the cref. The default
|
|
|
|
|
implementation of `const_missing` raises `NameError`, but it can be overridden.
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
|
|
|
|
Rails autoloading **does not emulate this algorithm**, but its starting point is
|
|
|
|
|
the name of the constant to be autoloaded, and the cref. See more in [Relative
|
|
|
|
|
References](#relative-references).
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
#### Resolution Algorithm for Qualified Constants
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
|
|
|
|
Qualified constants look like this:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
Billing::Invoice
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
`Billing::Invoice` is composed of two constants: `Billing` is relative and is
|
|
|
|
|
resolved using the algorithm of the previous section; `Invoice` is qualified by
|
|
|
|
|
`Billing` and we are going to see its resolution next. Let's call *parent* to
|
|
|
|
|
that qualifying class or module object, that is, `Billing` in the example above.
|
|
|
|
|
The algorithm for qualified constants goes like this:
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
|
|
|
|
1. The constant is looked up in the parent and its ancestors.
|
|
|
|
|
|
2014-12-15 10:41:23 -05:00
|
|
|
|
2. If the lookup fails, `const_missing` is invoked in the parent. The default
|
|
|
|
|
implementation of `const_missing` raises `NameError`, but it can be overridden.
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
|
|
|
|
As you see, this algorithm is simpler than the one for relative constants. In
|
|
|
|
|
particular, the nesting plays no role here, and modules are not special-cased,
|
|
|
|
|
if neither they nor their ancestors have the constants, `Object` is **not**
|
|
|
|
|
checked.
|
|
|
|
|
|
|
|
|
|
Rails autoloading **does not emulate this algorithm**, but its starting point is
|
|
|
|
|
the name of the constant to be autoloaded, and the parent. See more in
|
|
|
|
|
[Qualified References](#qualified-references).
|
|
|
|
|
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 08:06:16 -05:00
|
|
|
|
Vocabulary
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
|
|
### Parent Namespaces
|
|
|
|
|
|
|
|
|
|
Given a string with a constant path we define its *parent namespace* to be the
|
|
|
|
|
string that results from removing its rightmost segment.
|
|
|
|
|
|
|
|
|
|
For example, the parent namespace of the string "A::B::C" is the string "A::B",
|
|
|
|
|
the parent namespace of "A::B" is "A", and the parent namespace of "A" is "".
|
|
|
|
|
|
|
|
|
|
The interpretation of a parent namespace when thinking about classes and modules
|
|
|
|
|
is tricky though. Let's consider a module M named "A::B":
|
|
|
|
|
|
|
|
|
|
* The parent namespace, "A", may not reflect nesting at a given spot.
|
|
|
|
|
|
|
|
|
|
* The constant `A` may no longer exist, some code could have removed it from
|
|
|
|
|
`Object`.
|
|
|
|
|
|
|
|
|
|
* If `A` exists, the class or module that was originally in `A` may not be there
|
|
|
|
|
anymore. For example, if after a constant removal there was another constant
|
|
|
|
|
assignment there would generally be a different object in there.
|
|
|
|
|
|
|
|
|
|
* In such case, it could even happen that the reassigned `A` held a new class or
|
|
|
|
|
module called also "A"!
|
|
|
|
|
|
|
|
|
|
* In the previous scenarios M would no longer be reachable through `A::B` but
|
|
|
|
|
the module object itself could still be alive somewhere and its name would
|
|
|
|
|
still be "A::B".
|
|
|
|
|
|
|
|
|
|
The idea of a parent namespace is at the core of the autoloading algorithms
|
|
|
|
|
and helps explain and understand their motivation intuitively, but as you see
|
|
|
|
|
that metaphor leaks easily. Given an edge case to reason about, take always into
|
2014-12-15 19:08:24 -05:00
|
|
|
|
account that by "parent namespace" the guide means exactly that specific string
|
2014-12-15 08:06:16 -05:00
|
|
|
|
derivation.
|
|
|
|
|
|
|
|
|
|
### Loading Mechanism
|
|
|
|
|
|
2014-12-15 12:54:09 -05:00
|
|
|
|
Rails autoloads files with `Kernel#load` when `config.cache_classes` is false,
|
2014-12-15 08:06:16 -05:00
|
|
|
|
the default in development mode, and with `Kernel#require` otherwise, the
|
|
|
|
|
default in production mode.
|
|
|
|
|
|
|
|
|
|
`Kernel#load` allows Rails to execute files more than once if [constant
|
|
|
|
|
reloading](#constant-reloading) is enabled.
|
|
|
|
|
|
|
|
|
|
This guide uses the word "load" freely to mean a given file is interpreted, but
|
|
|
|
|
the actual mechanism can be `Kernel#load` or `Kernel#require` depending on that
|
|
|
|
|
flag.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Autoloading Availability
|
|
|
|
|
------------------------
|
|
|
|
|
|
|
|
|
|
Rails is always able to autoload provided its environment is in place. For
|
|
|
|
|
example the `runner` command autoloads:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
$ bin/rails runner 'p User.column_names'
|
|
|
|
|
["id", "email", "created_at", "updated_at"]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The console autoloads, the test suite autoloads, and of course the application
|
|
|
|
|
autoloads.
|
|
|
|
|
|
|
|
|
|
By default, Rails eager loads the application files when it boots in production
|
|
|
|
|
mode, so most of the autoloading going on in development does not happen. But
|
|
|
|
|
autoloading may still be triggered during eager loading.
|
|
|
|
|
|
|
|
|
|
For example, given
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class BeachHouse < House
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
if `House` is still unknown when `app/models/beach_house.rb` is being eager
|
|
|
|
|
loaded, Rails autoloads it.
|
|
|
|
|
|
|
|
|
|
|
2014-12-14 18:57:17 -05:00
|
|
|
|
autoload_paths
|
|
|
|
|
--------------
|
|
|
|
|
|
|
|
|
|
As you probably know, when `require` gets a relative file name:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
require 'erb'
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Ruby looks for the file in the directories listed in `$LOAD_PATH`. That is, Ruby
|
2014-12-16 03:16:58 -05:00
|
|
|
|
iterates over all its directories and for each one of them checks whether they
|
|
|
|
|
have a file called "erb.rb", or "erb.so", or "erb.o", or "erb.dll". If it finds
|
|
|
|
|
any of them, the interpreter loads it and ends the search. Otherwise, it tries
|
|
|
|
|
again in the next directory of the list. If the list gets exhausted, `LoadError`
|
|
|
|
|
is raised.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
We are going to cover how constant autoloading works in more detail later, but
|
2014-12-16 03:16:58 -05:00
|
|
|
|
the idea is that when a constant like `Post` is hit and missing, if there's a
|
|
|
|
|
`post.rb` file for example in `app/models` Rails is going to find it, evaluate
|
|
|
|
|
it, and have `Post` defined as a side-effect.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-16 03:16:58 -05:00
|
|
|
|
Alright, Rails has a collection of directories similar to `$LOAD_PATH` in which
|
|
|
|
|
to lookup that `post.rb`. That collection is called `autoload_paths` and by
|
2014-12-14 18:57:17 -05:00
|
|
|
|
default it contains:
|
|
|
|
|
|
|
|
|
|
* All subdirectories of `app` in the application and engines. For example,
|
|
|
|
|
`app/controllers`. They do not need to be the default ones, any custom
|
|
|
|
|
directories like `app/workers` belong automatically to `autoload_paths`.
|
|
|
|
|
|
|
|
|
|
* Any existing second level directories called `app/*/concerns` in the
|
|
|
|
|
application and engines.
|
|
|
|
|
|
|
|
|
|
* The directory `test/mailers/previews`.
|
|
|
|
|
|
|
|
|
|
Also, this collection is configurable via `config.autoload_paths`. For example,
|
|
|
|
|
`lib` was in the list years ago, but no longer is. An application can opt-in
|
|
|
|
|
throwing this to `config/application.rb`:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
config.autoload_paths += "#{Rails.root}/lib"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The value of `autoload_paths` can be inspected. In a just generated application
|
|
|
|
|
it is (edited):
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
$ bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths'
|
|
|
|
|
.../app/assets
|
|
|
|
|
.../app/controllers
|
|
|
|
|
.../app/helpers
|
|
|
|
|
.../app/mailers
|
|
|
|
|
.../app/models
|
|
|
|
|
.../app/controllers/concerns
|
|
|
|
|
.../app/models/concerns
|
|
|
|
|
.../test/mailers/previews
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
INFO. `autoload_paths` is computed and cached during the initialization process.
|
|
|
|
|
The application needs to be restarted to reflect any changes in the directory
|
|
|
|
|
structure.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Autoloading Algorithms
|
|
|
|
|
----------------------
|
|
|
|
|
|
|
|
|
|
### Relative References
|
|
|
|
|
|
2014-12-15 04:41:34 -05:00
|
|
|
|
A relative constant reference may appear in several places, for example, in
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class PostsController < ApplicationController
|
|
|
|
|
def index
|
|
|
|
|
@posts = Post.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 04:41:34 -05:00
|
|
|
|
all three constant references are relative.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
#### Constants after the `class` and `module` Keywords
|
|
|
|
|
|
|
|
|
|
Ruby performs a lookup for the constant that follows a `class` or `module`
|
|
|
|
|
keyword because it needs to know if the class or module is going to be created
|
|
|
|
|
or reopened.
|
|
|
|
|
|
|
|
|
|
If the constant is not defined at that point it is not considered to be a
|
|
|
|
|
missing constant, autoloading is **not** triggered.
|
|
|
|
|
|
|
|
|
|
So, in the previous example, if `PostsController` is not defined when the file
|
|
|
|
|
is interpreted Rails autoloading is not going to be triggered, Ruby will just
|
|
|
|
|
define the controller.
|
|
|
|
|
|
|
|
|
|
#### Top-Level Constants
|
|
|
|
|
|
2014-12-15 04:41:34 -05:00
|
|
|
|
On the contrary, if `ApplicationController` is unknown, the constant is
|
|
|
|
|
considered missing and an autoload is going to be attempted by Rails.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
In order to load `ApplicationController`, Rails iterates over `autoload_paths`.
|
|
|
|
|
First checks if `app/assets/application_controller.rb` exists. If it does not,
|
|
|
|
|
which is normally the case, it continues and finds
|
|
|
|
|
`app/controllers/application_controller.rb`.
|
|
|
|
|
|
|
|
|
|
If the file defines the constant `ApplicationController` all is fine, otherwise
|
|
|
|
|
`LoadError` is raised:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
unable to autoload constant ApplicationController, expected
|
|
|
|
|
<full path to application_controller.rb> to define it (LoadError)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
INFO. Rails does not require the value of autoloaded constants to be a class or
|
|
|
|
|
module object. For example, if the file `app/models/max_clients.rb` defines
|
|
|
|
|
`MAX_CLIENTS = 100` autoloading `MAX_CLIENTS` works just fine.
|
|
|
|
|
|
|
|
|
|
#### Namespaces
|
|
|
|
|
|
|
|
|
|
Autoloading `ApplicationController` looks directly under the directories of
|
|
|
|
|
`autoload_paths` because the nesting in that spot is empty. The situation of
|
|
|
|
|
`Post` is different, the nesting in that line is `[PostsController]` and support
|
|
|
|
|
for namespaces comes into play.
|
|
|
|
|
|
|
|
|
|
The basic idea is that given
|
|
|
|
|
|
2014-12-15 04:41:34 -05:00
|
|
|
|
```ruby
|
2014-12-14 18:57:17 -05:00
|
|
|
|
module Admin
|
|
|
|
|
class BaseController < ApplicationController
|
|
|
|
|
@@all_roles = Role.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
to autoload `Role` we are going to check if it is defined in the current or
|
|
|
|
|
parent namespaces, one at a time. So, conceptually we want to try to autoload
|
|
|
|
|
any of
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Admin::BaseController::Role
|
|
|
|
|
Admin::Role
|
|
|
|
|
Role
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
in that order. That's the idea. To do so, Rails looks in `autoload_paths`
|
|
|
|
|
respectively for file names like these:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
admin/base_controller/role.rb
|
|
|
|
|
admin/role.rb
|
|
|
|
|
role.rb
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
modulus some additional directory lookups we are going to cover soon.
|
|
|
|
|
|
2014-12-15 13:11:32 -05:00
|
|
|
|
INFO. `'Constant::Name'.underscore` gives the relative path without extension of
|
2014-12-14 18:57:17 -05:00
|
|
|
|
the file name where `Constant::Name` is expected to be defined.
|
|
|
|
|
|
2014-12-15 19:08:24 -05:00
|
|
|
|
Let's see how Rails autoloads the `Post` constant in the `PostsController`
|
2014-12-14 18:57:17 -05:00
|
|
|
|
above assuming the application has a `Post` model defined in
|
|
|
|
|
`app/models/post.rb`.
|
|
|
|
|
|
|
|
|
|
First it checks for `posts_controller/post.rb` in `autoload_paths`:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
app/assets/posts_controller/post.rb
|
|
|
|
|
app/controllers/posts_controller/post.rb
|
|
|
|
|
app/helpers/posts_controller/post.rb
|
|
|
|
|
...
|
|
|
|
|
test/mailers/previews/posts_controller/post.rb
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Since the lookup is exhausted without success, a similar search for a directory
|
2014-12-15 04:41:34 -05:00
|
|
|
|
is performed, we are going to see why in the [next section](#automatic-modules):
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
app/assets/posts_controller/post
|
|
|
|
|
app/controllers/posts_controller/post
|
|
|
|
|
app/helpers/posts_controller/post
|
|
|
|
|
...
|
|
|
|
|
test/mailers/previews/posts_controller/post
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If all those attempts fail, then Rails starts the lookup again in the parent
|
|
|
|
|
namespace. In this case only the top-level remains:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
app/assets/post.rb
|
|
|
|
|
app/controllers/post.rb
|
|
|
|
|
app/helpers/post.rb
|
|
|
|
|
app/mailers/post.rb
|
|
|
|
|
app/models/post.rb
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
A matching file is found in `app/models/post.rb`. The lookup stops there and the
|
|
|
|
|
file is loaded. If the file actually defines `Post` all is fine, otherwise
|
|
|
|
|
`LoadError` is raised.
|
|
|
|
|
|
|
|
|
|
### Qualified References
|
|
|
|
|
|
|
|
|
|
When a qualified constant is missing Rails does not look for it in the parent
|
2014-12-15 19:08:24 -05:00
|
|
|
|
namespaces. But there's a caveat: unfortunately, when a constant is missing
|
2014-12-14 18:57:17 -05:00
|
|
|
|
Rails is not able to say if the trigger was a relative or qualified reference.
|
|
|
|
|
|
|
|
|
|
For example, consider
|
|
|
|
|
|
|
|
|
|
```ruby
|
2014-12-15 03:22:21 -05:00
|
|
|
|
module Admin
|
2014-12-15 09:45:25 -05:00
|
|
|
|
User
|
2014-12-14 18:57:17 -05:00
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
and
|
|
|
|
|
|
|
|
|
|
```ruby
|
2014-12-15 09:45:25 -05:00
|
|
|
|
Admin::User
|
2014-12-14 18:57:17 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If `User` is missing, in either case all Rails knows is that a constant called
|
|
|
|
|
"User" was missing in a module called "Admin".
|
|
|
|
|
|
|
|
|
|
If there is a top-level `User` Ruby would resolve it in the former example, but
|
|
|
|
|
wouldn't in the latter. In general, Rails does not emulate the Ruby constant
|
|
|
|
|
resolution algorithms, but in this case it tries using the following heuristic:
|
|
|
|
|
|
|
|
|
|
> If none of the parent namespaces of the class or module has the missing
|
|
|
|
|
> constant then Rails assumes the reference is relative. Otherwise qualified.
|
|
|
|
|
|
|
|
|
|
For example, if this code triggers autoloading
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
Admin::User
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
and the `User` constant is already present in `Object`, it is not possible that
|
|
|
|
|
the situation is
|
|
|
|
|
|
|
|
|
|
```ruby
|
2014-12-15 03:22:21 -05:00
|
|
|
|
module Admin
|
2014-12-14 18:57:17 -05:00
|
|
|
|
User
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
because otherwise Ruby would have resolved `User` and no autoloading would have
|
|
|
|
|
been triggered in the first place. Thus, Rails assumes a qualified reference and
|
|
|
|
|
considers the file `admin/user.rb` and directory `admin/user` to be the only
|
|
|
|
|
valid options.
|
|
|
|
|
|
|
|
|
|
In practice this works quite well as long as the nesting matches all parent
|
|
|
|
|
namespaces respectively and the constants that make the rule apply are known at
|
|
|
|
|
that time.
|
|
|
|
|
|
|
|
|
|
But since autoloading happens on demand, if the top-level `User` by chance was
|
2014-12-15 03:22:21 -05:00
|
|
|
|
not yet loaded then Rails has no way to know whether `Admin::User` should load it
|
2014-12-14 18:57:17 -05:00
|
|
|
|
or raise `NameError`.
|
|
|
|
|
|
2014-12-15 19:08:24 -05:00
|
|
|
|
These kind of name conflicts are rare in practice but, in case there's one,
|
2014-12-14 18:57:17 -05:00
|
|
|
|
`require_dependency` provides a solution by making sure the constant needed to
|
|
|
|
|
trigger the heuristic is defined in the conflicting place.
|
|
|
|
|
|
|
|
|
|
### Automatic Modules
|
|
|
|
|
|
|
|
|
|
When a module acts as a namespace, Rails does not require the application to
|
|
|
|
|
defines a file for it, a directory matching the namespace is enough.
|
|
|
|
|
|
2014-12-16 03:16:58 -05:00
|
|
|
|
Suppose an application has a backoffice whose controllers are stored in
|
2014-12-14 18:57:17 -05:00
|
|
|
|
`app/controllers/admin`. If the `Admin` module is not yet loaded when
|
|
|
|
|
`Admin::UsersController` is hit, Rails needs first to autoload the constant
|
|
|
|
|
`Admin`.
|
|
|
|
|
|
|
|
|
|
If `autoload_paths` has a file called `admin.rb` Rails is going to load that
|
|
|
|
|
one, but if there's no such file and a directory called `admin` is found, Rails
|
2014-12-15 04:41:34 -05:00
|
|
|
|
creates an empty module and assigns it to the `Admin` constant on the fly.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
### Generic Procedure
|
|
|
|
|
|
2014-12-15 09:30:12 -05:00
|
|
|
|
Relative references are reported to be missing in the cref where they were hit,
|
|
|
|
|
and qualified references are reported to be missing in their parent. (See
|
|
|
|
|
[Resolution Algorithm for Relative
|
|
|
|
|
Constants](#resolution-algorithm-for-relative-constants) at the beginning of
|
|
|
|
|
this guide for the definition of *cref*, and [Resolution Algorithm for Qualified
|
|
|
|
|
Constants](#resolution-algorithm-for-qualified-constants) for the definition of
|
|
|
|
|
*parent*.)
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 09:30:12 -05:00
|
|
|
|
The procedure to autoload constant `C` in an arbitrary situation is as follows:
|
2014-12-15 09:03:31 -05:00
|
|
|
|
|
2014-12-15 09:30:12 -05:00
|
|
|
|
```
|
|
|
|
|
if the class or module in which C is missing is Object
|
2014-12-14 18:57:17 -05:00
|
|
|
|
let ns = ''
|
|
|
|
|
else
|
2014-12-15 09:30:12 -05:00
|
|
|
|
let M = the class or module in which C is missing
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
if M is anonymous
|
|
|
|
|
let ns = ''
|
|
|
|
|
else
|
|
|
|
|
let ns = M.name
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
loop do
|
|
|
|
|
# Look for a regular file.
|
|
|
|
|
for dir in autoload_paths
|
|
|
|
|
if the file "#{dir}/#{ns.underscore}/c.rb" exists
|
|
|
|
|
load/require "#{dir}/#{ns.underscore}/c.rb"
|
|
|
|
|
|
|
|
|
|
if C is now defined
|
|
|
|
|
return
|
|
|
|
|
else
|
|
|
|
|
raise LoadError
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Look for an automatic module.
|
|
|
|
|
for dir in autoload_paths
|
|
|
|
|
if the directory "#{dir}/#{ns.underscore}/c" exists
|
|
|
|
|
if ns is an empty string
|
|
|
|
|
let C = Module.new in Object and return
|
|
|
|
|
else
|
|
|
|
|
let C = Module.new in ns.constantize and return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if ns is empty
|
|
|
|
|
# We reached the top-level without finding the constant.
|
|
|
|
|
raise NameError
|
|
|
|
|
else
|
|
|
|
|
if C exists in any of the parent namespaces
|
|
|
|
|
# Qualified constants heuristic.
|
|
|
|
|
raise NameError
|
|
|
|
|
else
|
|
|
|
|
# Try again in the parent namespace.
|
|
|
|
|
let ns = the parent namespace of ns and retry
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
require_dependency
|
|
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
Constant autoloading is triggered on demand and therefore code that uses a
|
|
|
|
|
certain constant may have it already defined or may trigger an autoload. That
|
|
|
|
|
depends on the execution path and it may vary between runs.
|
|
|
|
|
|
|
|
|
|
There are times, however, in which you want to make sure a certain constant is
|
|
|
|
|
known when the execution reaches some code. `require_dependency` provides a way
|
|
|
|
|
to load a file using the current [loading mechanism](#loading-mechanism), and
|
|
|
|
|
keeping track of constants defined in that file as if they were autoloaded to
|
|
|
|
|
have them reloaded as needed.
|
|
|
|
|
|
|
|
|
|
`require_dependency` is rarely needed, but see a couple of use-cases in
|
|
|
|
|
[Autoloading and STI](#autoloading-and-sti) and [When Constants aren't
|
|
|
|
|
Triggered](#when-constants-aren-t-missed).
|
|
|
|
|
|
|
|
|
|
WARNING. Unlike autoloading, `require_dependency` does not expect the file to
|
|
|
|
|
define any particular constant. Exploiting this behavior would be a bad practice
|
|
|
|
|
though, file and constant paths should match.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Constant Reloading
|
|
|
|
|
------------------
|
|
|
|
|
|
|
|
|
|
When `config.cache_classes` is false Rails is able to reload autoloaded
|
|
|
|
|
constants.
|
|
|
|
|
|
|
|
|
|
For example, in you're in a console session and edit some file behind the
|
|
|
|
|
scenes, the code can be reloaded with the `reload!` command:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
> reload!
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
When the application runs, code is reloaded when something relevant to this
|
|
|
|
|
logic changes. In order to do that, Rails monitors a number of things:
|
|
|
|
|
|
|
|
|
|
* `config/routes.rb`.
|
|
|
|
|
|
|
|
|
|
* Locales.
|
|
|
|
|
|
|
|
|
|
* Ruby files under `autoload_paths`.
|
|
|
|
|
|
|
|
|
|
* `db/schema.rb` and `db/structure.sql`.
|
|
|
|
|
|
|
|
|
|
If anything in there changes, there is a middleware that detects it and reloads
|
|
|
|
|
the code.
|
|
|
|
|
|
|
|
|
|
Autoloading keeps track of autoloaded constants. Reloading is implemented by
|
|
|
|
|
removing them all from their respective classes and modules using
|
|
|
|
|
`Module#remove_const`. That way, when the code goes on, those constants are
|
2014-12-15 10:39:34 -05:00
|
|
|
|
going to be unknown again, and files reloaded on demand.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
INFO. This is an all-or-nothing operation, Rails does not attempt to reload only
|
|
|
|
|
what changed since dependencies between classes makes that really tricky.
|
|
|
|
|
Instead, everything is wiped.
|
|
|
|
|
|
|
|
|
|
|
2014-12-15 04:21:27 -05:00
|
|
|
|
Module#autoload isn't Involved
|
2014-12-15 04:14:13 -05:00
|
|
|
|
------------------------------
|
|
|
|
|
|
2014-12-15 04:21:27 -05:00
|
|
|
|
`Module#autoload` provides a lazy way to load constants that is fully integrated
|
2014-12-15 04:14:13 -05:00
|
|
|
|
with the Ruby constant lookup algorithms, dynamic constant API, etc. It is quite
|
|
|
|
|
transparent.
|
|
|
|
|
|
|
|
|
|
Rails internals make extensive use of it to defer as much work as possible from
|
|
|
|
|
the boot process. But constant autoloading in Rails is **not** implemented with
|
2014-12-15 04:21:27 -05:00
|
|
|
|
`Module#autoload`.
|
2014-12-15 04:14:13 -05:00
|
|
|
|
|
2014-12-15 04:21:27 -05:00
|
|
|
|
One possible implementation based on `Module#autoload` would be to walk the
|
2014-12-15 04:14:13 -05:00
|
|
|
|
application tree and issue `autoload` calls that map existing file names to
|
2014-12-15 10:39:34 -05:00
|
|
|
|
their conventional constant name.
|
2014-12-15 04:14:13 -05:00
|
|
|
|
|
|
|
|
|
There are a number of reasons that prevent Rails from using that implementation.
|
|
|
|
|
|
2014-12-15 04:21:27 -05:00
|
|
|
|
For example, `Module#autoload` is only capable of loading files using `require`,
|
2014-12-15 04:14:13 -05:00
|
|
|
|
so reloading would not be possible. Not only that, it uses an internal `require`
|
|
|
|
|
which is not `Kernel#require`.
|
|
|
|
|
|
|
|
|
|
Then, it provides no way to remove declarations in case a file is deleted. If a
|
|
|
|
|
constant gets removed with `Module#remove_const` its `autoload` is not triggered
|
|
|
|
|
again. Also, it doesn't support qualified names, so files with namespaces should
|
|
|
|
|
be interpreted during the walk tree to install their own `autoload` calls, but
|
|
|
|
|
those files could have constant references not yet configured.
|
|
|
|
|
|
2014-12-15 04:21:27 -05:00
|
|
|
|
An implementation based on `Module#autoload` would be awesome but, as you see,
|
2014-12-15 04:14:13 -05:00
|
|
|
|
at least as of today it is not possible. Constant autoloading in Rails is
|
|
|
|
|
implemented with `Module#const_missing`, and that's why it has its own contract,
|
|
|
|
|
documented in this guide.
|
|
|
|
|
|
|
|
|
|
|
2014-12-14 18:57:17 -05:00
|
|
|
|
Common Gotchas
|
|
|
|
|
--------------
|
|
|
|
|
|
|
|
|
|
### Nesting and Qualified Constants
|
|
|
|
|
|
|
|
|
|
Let's consider
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
module Admin
|
|
|
|
|
class UsersController < ApplicationController
|
|
|
|
|
def index
|
|
|
|
|
@users = User.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
and
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class Admin::UsersController < ApplicationController
|
|
|
|
|
def index
|
|
|
|
|
@users = User.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
To resolve `User` Ruby checks `Admin` in the former case, but it does not in
|
|
|
|
|
the latter because it does not belong to the nesting. (See [Nesting](#nesting)
|
|
|
|
|
and [Resolution Algorithms](#resolution- algorithms).)
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 04:41:34 -05:00
|
|
|
|
Unfortunately Rails autoloading does not know the nesting in the spot where the
|
2014-12-14 18:57:17 -05:00
|
|
|
|
constant was missing and so it is not able to act as Ruby would. In particular,
|
2014-12-15 17:08:16 -05:00
|
|
|
|
`Admin::User` will get autoloaded in either case.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
Albeit qualified constants with `class` and `module` keywords may technically
|
2014-12-15 10:39:34 -05:00
|
|
|
|
work with autoloading in some cases, it is preferable to use relative constants
|
2014-12-14 18:57:17 -05:00
|
|
|
|
instead:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
module Admin
|
|
|
|
|
class UsersController < ApplicationController
|
|
|
|
|
def index
|
|
|
|
|
@users = User.all
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Autoloading and STI
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Single Table Inheritance (STI) is a feature of Active Record that easies
|
|
|
|
|
storing a hierarchy of models in one single table. The API of such models is
|
|
|
|
|
aware of the hierarchy and encapsulates some common needs. For example, given
|
|
|
|
|
these classes:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# app/models/polygon.rb
|
|
|
|
|
class Polygon < ActiveRecord::Base
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# app/models/triangle.rb
|
|
|
|
|
class Triangle < Polygon
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# app/models/rectangle.rb
|
|
|
|
|
class Rectangle < Polygon
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`Triangle.create` creates a row that represents a triangle, and
|
2014-12-15 17:08:16 -05:00
|
|
|
|
`Rectangle.create` creates a row that represents a rectangle. If `id` is the
|
|
|
|
|
ID of an existing record, `Polygon.find(id)` returns an object of the correct
|
|
|
|
|
type.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Methods that operate on collections are also aware of the hierarchy. For
|
|
|
|
|
example, `Polygon.all` returns all the records of the table, because all
|
2014-12-14 18:57:17 -05:00
|
|
|
|
rectangles and triangles are polygons. Active Record takes care of returning
|
|
|
|
|
instances of their corresponding class in the result set.
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Types are autoloaded as needed. For example, if `Polygon.first` is a rectangle
|
|
|
|
|
and `Rectangle` has not yet been loaded, Active Record autoloads it and the
|
|
|
|
|
record is correctly instantiated.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
All good, but if instead of performing queries based on the root class we need
|
2014-12-15 17:08:16 -05:00
|
|
|
|
to work on some subclass, things get interesting.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
While working with `Polygon` you do not need to be aware of all its descendants,
|
|
|
|
|
because anything in the table is by definition a polygon, but when working with
|
|
|
|
|
subclasses Active Record needs to be able to enumerate the types it is looking
|
|
|
|
|
for. Let’s see an example.
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
`Rectangle.all` only loads rectangles by adding a type constraint to the query:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
SELECT "polygons".* FROM "polygons"
|
|
|
|
|
WHERE "polygons"."type" IN ("Rectangle")
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Let’s introduce now a subclass of `Rectangle`:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# app/models/square.rb
|
|
|
|
|
class Square < Rectangle
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
`Rectangle.all` should now return rectangles **and** squares:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
SELECT "polygons".* FROM "polygons"
|
|
|
|
|
WHERE "polygons"."type" IN ("Rectangle", "Square")
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
But there’s a caveat here: How does Active Record know that the class `Square`
|
|
|
|
|
exists at all?
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
Even if the file `app/models/square.rb` exists and defines the `Square` class,
|
|
|
|
|
if no code yet used that class, `Rectangle.all` issues the query
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
SELECT "polygons".* FROM "polygons"
|
|
|
|
|
WHERE "polygons"."type" IN ("Rectangle")
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
That is not a bug, the query includes all *known* descendants of `Rectangle`.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
A way to ensure this works correctly regardless of the order of execution is to
|
|
|
|
|
load the leaves of the tree by hand at the bottom of the file that defines the
|
|
|
|
|
root class:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# app/models/polygon.rb
|
|
|
|
|
class Polygon < ActiveRecord::Base
|
|
|
|
|
end
|
|
|
|
|
require_dependency ‘square’
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Only the leaves that are **at least grandchildren** have to be loaded that
|
2014-12-15 19:08:24 -05:00
|
|
|
|
way. Direct subclasses do not need to be preloaded and, if the hierarchy is
|
|
|
|
|
deeper, intermediate classes will be autoloaded recursively from the bottom
|
2014-12-15 17:08:16 -05:00
|
|
|
|
because their constant will appear in the class definitions as superclass.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
### Autoloading and `require`
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Files defining constants to be autoloaded should never be `require`d:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
require 'user' # DO NOT DO THIS
|
|
|
|
|
|
|
|
|
|
class UsersController < ApplicationController
|
|
|
|
|
...
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
There are two possible gotchas here in development mode:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
1. If `User` is autoloaded before reaching the `require`, `app/models/user.rb`
|
|
|
|
|
runs again because `load` does not update `$LOADED_FEATURES`.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
2. If the `require` runs first Rails does not mark `User` as an autoloaded
|
|
|
|
|
constant and changes to `app/models/user.rb` aren't reloaded.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Just follow the flow and use constant autoloading always, never mix
|
|
|
|
|
autoloading and `require`. As a last resort, if some file absolutely needs to
|
|
|
|
|
load a certain file use `require_dependency` to play nice with constant
|
|
|
|
|
autoloading. This option is rarely needed in practice, though.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
Of course, using `require` in autoloaded files to load ordinary 3rd party
|
2014-12-15 17:08:16 -05:00
|
|
|
|
libraries is fine, and Rails is able to distinguish their constants, they are
|
2014-12-14 18:57:17 -05:00
|
|
|
|
not marked as autoloaded.
|
|
|
|
|
|
|
|
|
|
### Autoloading and Initializers
|
|
|
|
|
|
|
|
|
|
Consider this assignment in `config/initializers/set_auth_service.rb`:
|
|
|
|
|
|
|
|
|
|
```ruby
|
2014-12-15 17:08:16 -05:00
|
|
|
|
AUTH_SERVICE = if Rails.env.production?
|
|
|
|
|
RealAuthService
|
|
|
|
|
else
|
|
|
|
|
MockedAuthService
|
|
|
|
|
end
|
2014-12-14 18:57:17 -05:00
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
The purpose of this setup would be that the application uses the class that
|
|
|
|
|
corresponds to the environment via `AUTH_SERVICE`. In development mode
|
|
|
|
|
`MockedAuthService` gets autoloaded when the initializer runs. Let’s suppose
|
|
|
|
|
we do some requests, change its implementation, and hit the application again.
|
|
|
|
|
To our surprise the changes are not reflected. Why?
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
As [we saw earlier](#constant-reloading), Rails removes autoloaded constants,
|
|
|
|
|
but `AUTH_SERVICE` stores the original class object. Stale, non-reachable
|
|
|
|
|
using the original constant, but perfectly functional.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
The following code summarizes the situation:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class C
|
|
|
|
|
def quack
|
|
|
|
|
'quack!'
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
X = C
|
|
|
|
|
Object.instance_eval { remove_const(:C) }
|
|
|
|
|
X.new.quack # => quack!
|
|
|
|
|
X.name # => C
|
|
|
|
|
C # => uninitialized constant C (NameError)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Because of that, it is not a good idea to autoload constants on application
|
|
|
|
|
initialization.
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
In the case above we could implement a dynamic access point:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
2014-12-15 17:08:16 -05:00
|
|
|
|
# app/models/auth_service.rb
|
2014-12-14 18:57:17 -05:00
|
|
|
|
class AuthService
|
|
|
|
|
if Rails.env.production?
|
|
|
|
|
def self.instance
|
|
|
|
|
RealAuthService
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
def self.instance
|
|
|
|
|
MockedAuthService
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
and have the application use `AuthService.instance` instead. `AuthService`
|
|
|
|
|
would be loaded on demand and be autoload-friendly.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
### `require_dependency` and Initializers
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
As we saw before, `require_dependency` loads files in an autoloading-friendly
|
2014-12-14 18:57:17 -05:00
|
|
|
|
way. Normally, though, such a call does not make sense in an initializer.
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
One could think about doing some [`require_dependency`](#require-dependency)
|
|
|
|
|
calls in an initializer to make sure certain constants are loaded upfront, for
|
|
|
|
|
example as an attempt to address the [gotcha with STIs](#autoloading-and-sti).
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Problem is, in development mode [autoloaded constants are wiped](#constant-reloading)
|
2014-12-15 19:08:24 -05:00
|
|
|
|
if there is any relevant change in the file system. If that happens then
|
2014-12-15 17:08:16 -05:00
|
|
|
|
we are in the very same situation the initializer wanted to avoid!
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
Calls to `require_dependency` have to be strategically written in autoloaded
|
|
|
|
|
spots.
|
|
|
|
|
|
|
|
|
|
### When Constants aren't Missed
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Let's consider an `Image` model, superclass of `Hotel::Image`:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# app/models/image.rb
|
|
|
|
|
class Image
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# app/models/hotel/image.rb
|
|
|
|
|
module Hotel
|
|
|
|
|
class Image < Image
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
No matter which file is interpreted first, `app/models/hotel/image.rb` is
|
|
|
|
|
well-defined.
|
|
|
|
|
|
|
|
|
|
Now consider a third file with this apparently harmless code:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# app/models/hotel/poster.rb
|
|
|
|
|
module Hotel
|
|
|
|
|
class Poster < Image
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The intention is to subclass `Hotel::Image`, but which is actually the
|
2014-12-15 17:08:16 -05:00
|
|
|
|
superclass of `Hotel::Poster`? Well, it depends on the order of execution:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
1. If neither `app/models/image.rb` nor `app/models/hotel/image.rb` have been
|
|
|
|
|
loaded at that point, the superclass is `Hotel::Image` because Rails is told
|
|
|
|
|
`Hotel` is missing a constant called "Image" and loads
|
|
|
|
|
`app/models/hotel/image.rb`. Good.
|
|
|
|
|
|
|
|
|
|
2. If `app/models/hotel/image.rb` has been loaded at that point, the superclass
|
|
|
|
|
is `Hotel::Image` because Ruby is able to resolve the constant. Good.
|
|
|
|
|
|
|
|
|
|
3. Lastly, if only `app/models/image.rb` has been loaded so far, the superclass
|
|
|
|
|
is `Image`. Gotcha!
|
|
|
|
|
|
|
|
|
|
The last scenario (3) may be surprising. Why isn't `Hotel::Image` autoloaded?
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Because Ruby is able to resolve `Image` as a top-level constant, so
|
|
|
|
|
autoloading does not even get a chance.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
Most of the time, these kind of ambiguities can be resolved using qualified
|
|
|
|
|
constants. In this case we would write
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
module Hotel
|
|
|
|
|
class Poster < Hotel::Image
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
That class definition now is robust.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 19:08:24 -05:00
|
|
|
|
It is interesting to note here that the fix works because `Hotel` is a module, and
|
2014-12-14 18:57:17 -05:00
|
|
|
|
`Hotel::Image` won’t look for `Image` in `Object` as it would if `Hotel` was a
|
2014-12-15 10:41:23 -05:00
|
|
|
|
class with `Object` in its ancestors. If `Hotel` was a class we would resort to
|
|
|
|
|
loading `Hotel::Image` with `require_dependency`. Furthermore, with that
|
|
|
|
|
solution the qualified name would no longer be necessary.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
### Autoloading within Singleton Classes
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
Let's suppose we have these class definitions:
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# app/models/hotel/services.rb
|
|
|
|
|
module Hotel
|
|
|
|
|
class Services
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# app/models/hotel/geo_location.rb
|
|
|
|
|
module Hotel
|
|
|
|
|
class GeoLocation
|
|
|
|
|
class << self
|
|
|
|
|
Services
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
If `Hotel::Services` is known by the time `app/models/hotel/geo_location.rb`
|
|
|
|
|
is being loaded, `Services` is resolved by Ruby because `Hotel` belongs to the
|
|
|
|
|
nesting when the singleton class of `Hotel::GeoLocation` is opened.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
But if `Hotel::Services` is not known, Rails is not able to autoload it, the
|
|
|
|
|
application raises `NameError`.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
The reason is that autoloading is triggered for the singleton class, which is
|
2014-12-15 17:08:16 -05:00
|
|
|
|
anonymous, and as [we saw before](#generic-procedure), Rails only checks the
|
2014-12-15 04:41:34 -05:00
|
|
|
|
top-level namespace in that edge case.
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
An easy solution to this caveat is to qualify the constant:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
module Hotel
|
|
|
|
|
class GeoLocation
|
|
|
|
|
class << self
|
|
|
|
|
Hotel::Services
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Autoloading in `BasicObject`
|
|
|
|
|
|
|
|
|
|
Direct descendants of `BasicObject` do not have `Object` among their ancestors
|
|
|
|
|
and cannot resolve top-level constants:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class C < BasicObject
|
|
|
|
|
String # NameError: uninitialized constant C::String
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
When autoloading is involved that plot has a twist. Let's consider:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class C < BasicObject
|
|
|
|
|
def user
|
|
|
|
|
User # WRONG
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Since Rails checks the top-level namespace `User` gets autoloaded just fine the
|
|
|
|
|
first time the `user` method is invoked. You only get the exception if the
|
|
|
|
|
`User` constant is known at that point, in particular in a *second* call to
|
|
|
|
|
`user`:
|
|
|
|
|
|
2014-12-15 04:41:34 -05:00
|
|
|
|
```ruby
|
2014-12-14 18:57:17 -05:00
|
|
|
|
c = C.new
|
|
|
|
|
c.user # surprisingly fine, User
|
|
|
|
|
c.user # NameError: uninitialized constant C::User
|
|
|
|
|
```
|
|
|
|
|
|
2014-12-15 17:08:16 -05:00
|
|
|
|
because it detects a parent namespace already has the constant (see [Qualified
|
|
|
|
|
References](#qualified-references).)
|
2014-12-14 18:57:17 -05:00
|
|
|
|
|
|
|
|
|
As with pure Ruby, within the body of a direct descendant of `BasicObject` use
|
|
|
|
|
always absolute constant paths:
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class C < BasicObject
|
|
|
|
|
::String # RIGHT
|
|
|
|
|
|
|
|
|
|
def user
|
|
|
|
|
::User # RIGHT
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|