aboutsummaryrefslogtreecommitdiffstats
path: root/guides/source/constant_autoloading_and_reloading.md
diff options
context:
space:
mode:
authorVijay Dev <vijaydev.cse@gmail.com>2014-12-20 15:45:17 +0000
committerVijay Dev <vijaydev.cse@gmail.com>2014-12-20 15:46:15 +0000
commit34cd7e2b1a1b5be175d79c3233a97393b01b8bad (patch)
tree49c3fa7bad01374d4ab67c94b89734a2e0cc00ec /guides/source/constant_autoloading_and_reloading.md
parent194b965036776e002332914fa2612765be89e3b1 (diff)
downloadrails-34cd7e2b1a1b5be175d79c3233a97393b01b8bad.tar.gz
rails-34cd7e2b1a1b5be175d79c3233a97393b01b8bad.tar.bz2
rails-34cd7e2b1a1b5be175d79c3233a97393b01b8bad.zip
Renaming the autoloading guide [ci skip]
The term 'constant autoloading' can be mistakenly construed as 'constantly autoloading'.
Diffstat (limited to 'guides/source/constant_autoloading_and_reloading.md')
-rw-r--r--guides/source/constant_autoloading_and_reloading.md1297
1 files changed, 0 insertions, 1297 deletions
diff --git a/guides/source/constant_autoloading_and_reloading.md b/guides/source/constant_autoloading_and_reloading.md
deleted file mode 100644
index c39210383b..0000000000
--- a/guides/source/constant_autoloading_and_reloading.md
+++ /dev/null
@@ -1,1297 +0,0 @@
-Autoloading and Reloading Constants
-===================================
-
-This guide documents how constant autoloading and reloading works.
-
-After reading this guide, you will know:
-
-* Key aspects of Ruby constants
-* What is `autoload_paths`
-* How constant autoloading works
-* What is `require_dependency`
-* How constant reloading works
-* Solutions to common autoloading gotchas
-
---------------------------------------------------------------------------------
-
-
-Introduction
-------------
-
-Ruby on Rails allows applications to be written as if their code was preloaded.
-
-In a normal Ruby program classes need to load their dependencies:
-
-```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
-defined in files matching their name, couldn't their loading be automated
-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.
-
-Indeed, those features are provided by Ruby on Rails, where we just write
-
-```ruby
-class PostsController < ApplicationController
- def index
- @posts = Post.all
- end
-end
-```
-
-This guide documents how that works.
-
-
-Constants Refresher
--------------------
-
-While constants are trivial in most programming languages, they are a rich
-topic in Ruby.
-
-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.
-
-### Nesting
-
-Class and module definitions can be nested to create namespaces:
-
-```ruby
-module XML
- class SAXParser
- # (1)
- end
-end
-```
-
-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
-
-```ruby
-[XML::SAXParser, XML]
-```
-
-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.
-
-For instance, while this definition is similar to the previous one:
-
-```ruby
-class XML::SAXParser
- # (2)
-end
-```
-
-the nesting in (2) is different:
-
-```ruby
-[XML::SAXParser]
-```
-
-`XML` does not belong to it.
-
-We can see in this example that the name of a class or module that belongs to a
-certain nesting does not necessarily correlate with the namespaces at the spot.
-
-Even more, they are totally independent, take for instance
-
-```ruby
-module X::Y
- module A::B
- # (3)
- end
-end
-```
-
-The nesting in (3) consists of two module objects:
-
-```ruby
-[A::B, X::Y]
-```
-
-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`.
-
-The nesting is an internal stack maintained by the interpreter, and it gets
-modified according to these rules:
-
-* The class object following a `class` keyword gets pushed when its body is
-executed, and popped after it.
-
-* The module object following a `module` keyword gets pushed when its body is
-executed, and popped after it.
-
-* A singleton class opened with `class << object` gets pushed, and popped later.
-
-* 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.
-
-* 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.
-
-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
-differences between defining classes and modules in one way or another.
-
-The nesting at any given place can be inspected with `Module.nesting`.
-
-### 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)
-```
-
-including setting the name of the class as a side-effect:
-
-```ruby
-Project.name # => "Project"
-```
-
-Constant assignment has a special rule to make that happen: if the object
-being assigned is an anonymous class or module, Ruby sets the object's name to
-the name of the constant.
-
-INFO. From then on, what happens to the constant and the instance does not
-matter. For example, the constant could be deleted, the class object could be
-assigned to a different constant, be stored in no constant anymore, etc. Once
-the name is set, it doesn't change.
-
-Similarly, module creation using the `module` keyword as in
-
-```ruby
-module Admin
-end
-```
-
-performs a constant assignment equivalent to
-
-```ruby
-Admin = Module.new
-```
-
-including setting the name as a side-effect:
-
-```ruby
-Admin.name # => "Admin"
-```
-
-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
-`class` and `module` keywords. But both idioms result in the same constant
-assignment.
-
-Thus, when one informally says "the `String` class", that really means: the
-class object stored in the constant called "String" in the class object stored
-in the `Object` constant. `String` is otherwise an ordinary Ruby constant and
-everything related to constants such as resolution algorithms applies to it.
-
-Likewise, in the controller
-
-```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
-a constant table; think of it as a hash table.
-
-Let's analyze an example to really understand what that means. While common
-abuses of language like "the `String` class" are convenient, the exposition is
-going to be precise here for didactic purposes.
-
-Let's consider the following module definition:
-
-```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.
-Said entry associates the name "Colors" to a newly created module object.
-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`
-constant. That entry maps the name "RED" to the string "0xff0000".
-
-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.
-
-Pay special attention in the previous paragraphs to the distinction between
-class and module objects, constant names, and value objects associated to them
-in constant tables.
-
-### Resolution Algorithms
-
-#### Resolution Algorithm for Relative Constants
-
-At any given place in the code, let's define *cref* to be the first element of
-the nesting if it is not empty, or `Object` otherwise.
-
-Without getting too much into the details, the resolution algorithm for relative
-constant references goes like this:
-
-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.
-
-3. If not found, `const_missing` is invoked on the cref. The default
-implementation of `const_missing` raises `NameError`, but it can be overridden.
-
-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](#autoloading-algorithms-relative-references).
-
-#### Resolution Algorithm for Qualified Constants
-
-Qualified constants look like this:
-
-```ruby
-Billing::Invoice
-```
-
-`Billing::Invoice` is composed of two constants: `Billing` is relative and is
-resolved using the algorithm of the previous section.
-
-INFO. Leading colons would make the first segment absolute rather than
-relative: `::Billing::Invoice`. That would force `Billing` to be looked up
-only as a top-level constant.
-
-`Invoice` on the other hand 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:
-
-1. The constant is looked up in the parent and its ancestors.
-
-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.
-
-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).
-
-
-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
-account that by "parent namespace" the guide means exactly that specific string
-derivation.
-
-### Loading Mechanism
-
-Rails autoloads files with `Kernel#load` when `config.cache_classes` is false,
-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.
-
-
-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
-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.
-
-We are going to cover how constant autoloading works in more detail later, but
-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.
-
-Alright, Rails has a collection of directories similar to `$LOAD_PATH` in which
-to look up `post.rb`. That collection is called `autoload_paths` and by
-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
-by adding 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
-
-A relative constant reference may appear in several places, for example, in
-
-```ruby
-class PostsController < ApplicationController
- def index
- @posts = Post.all
- end
-end
-```
-
-all three constant references are relative.
-
-#### 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
-
-On the contrary, if `ApplicationController` is unknown, the constant is
-considered missing and an autoload is going to be attempted by Rails.
-
-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
-
-```ruby
-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.
-
-INFO. `'Constant::Name'.underscore` gives the relative path without extension of
-the file name where `Constant::Name` is expected to be defined.
-
-Let's see how Rails autoloads the `Post` constant in the `PostsController`
-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
-is performed, we are going to see why in the [next section](#automatic-modules):
-
-```
-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
-namespaces. But there is a caveat: When a constant is missing, Rails is
-unable to tell if the trigger was a relative reference or a qualified one.
-
-For example, consider
-
-```ruby
-module Admin
- User
-end
-```
-
-and
-
-```ruby
-Admin::User
-```
-
-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
-module Admin
- 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.
-
-However, autoloading happens on demand. If by chance the top-level `User` was
-not yet loaded, then Rails assumes a relative reference by contract.
-
-Naming conflicts of this kind are rare in practice, but if one occurs,
-`require_dependency` provides a solution by ensuring that 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.
-
-Suppose an application has a back office whose controllers are stored in
-`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
-creates an empty module and assigns it to the `Admin` constant on the fly.
-
-### Generic Procedure
-
-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*.)
-
-The procedure to autoload constant `C` in an arbitrary situation is as follows:
-
-```
-if the class or module in which C is missing is Object
- let ns = ''
-else
- let M = the class or module in which C is missing
-
- 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
-going to be unknown again, and files reloaded on demand.
-
-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.
-
-
-Module#autoload isn't Involved
-------------------------------
-
-`Module#autoload` provides a lazy way to load constants that is fully integrated
-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
-`Module#autoload`.
-
-One possible implementation based on `Module#autoload` would be to walk the
-application tree and issue `autoload` calls that map existing file names to
-their conventional constant name.
-
-There are a number of reasons that prevent Rails from using that implementation.
-
-For example, `Module#autoload` is only capable of loading files using `require`,
-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.
-
-An implementation based on `Module#autoload` would be awesome but, as you see,
-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.
-
-
-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
-```
-
-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).)
-
-Unfortunately Rails autoloading does not know the nesting in the spot where the
-constant was missing and so it is not able to act as Ruby would. In particular,
-`Admin::User` will get autoloaded in either case.
-
-Albeit qualified constants with `class` and `module` keywords may technically
-work with autoloading in some cases, it is preferable to use relative constants
-instead:
-
-```ruby
-module Admin
- class UsersController < ApplicationController
- def index
- @users = User.all
- end
- end
-end
-```
-
-### Autoloading and STI
-
-Single Table Inheritance (STI) is a feature of Active Record that enables
-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:
-
-```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
-`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.
-
-Methods that operate on collections are also aware of the hierarchy. For
-example, `Polygon.all` returns all the records of the table, because all
-rectangles and triangles are polygons. Active Record takes care of returning
-instances of their corresponding class in the result set.
-
-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.
-
-All good, but if instead of performing queries based on the root class we need
-to work on some subclass, things get interesting.
-
-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.
-
-`Rectangle.all` only loads rectangles by adding a type constraint to the query:
-
-```sql
-SELECT "polygons".* FROM "polygons"
-WHERE "polygons"."type" IN ("Rectangle")
-```
-
-Let’s introduce now a subclass of `Rectangle`:
-
-```ruby
-# app/models/square.rb
-class Square < Rectangle
-end
-```
-
-`Rectangle.all` should now return rectangles **and** squares:
-
-```sql
-SELECT "polygons".* FROM "polygons"
-WHERE "polygons"."type" IN ("Rectangle", "Square")
-```
-
-But there’s a caveat here: How does Active Record know that the class `Square`
-exists at all?
-
-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")
-```
-
-That is not a bug, the query includes all *known* descendants of `Rectangle`.
-
-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’
-```
-
-Only the leaves that are **at least grandchildren** need to be loaded this
-way. Direct subclasses do not need to be preloaded. If the hierarchy is
-deeper, intermediate classes will be autoloaded recursively from the bottom
-because their constant will appear in the class definitions as superclass.
-
-### Autoloading and `require`
-
-Files defining constants to be autoloaded should never be `require`d:
-
-```ruby
-require 'user' # DO NOT DO THIS
-
-class UsersController < ApplicationController
- ...
-end
-```
-
-There are two possible gotchas here in development mode:
-
-1. If `User` is autoloaded before reaching the `require`, `app/models/user.rb`
-runs again because `load` does not update `$LOADED_FEATURES`.
-
-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.
-
-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.
-
-Of course, using `require` in autoloaded files to load ordinary 3rd party
-libraries is fine, and Rails is able to distinguish their constants, they are
-not marked as autoloaded.
-
-### Autoloading and Initializers
-
-Consider this assignment in `config/initializers/set_auth_service.rb`:
-
-```ruby
-AUTH_SERVICE = if Rails.env.production?
- RealAuthService
-else
- MockedAuthService
-end
-```
-
-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?
-
-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.
-
-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.
-
-In the case above we could implement a dynamic access point:
-
-```ruby
-# app/models/auth_service.rb
-class AuthService
- if Rails.env.production?
- def self.instance
- RealAuthService
- end
- else
- def self.instance
- MockedAuthService
- end
- end
-end
-```
-
-and have the application use `AuthService.instance` instead. `AuthService`
-would be loaded on demand and be autoload-friendly.
-
-### `require_dependency` and Initializers
-
-As we saw before, `require_dependency` loads files in an autoloading-friendly
-way. Normally, though, such a call does not make sense in an initializer.
-
-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).
-
-Problem is, in development mode [autoloaded constants are wiped](#constant-reloading)
-if there is any relevant change in the file system. If that happens then
-we are in the very same situation the initializer wanted to avoid!
-
-Calls to `require_dependency` have to be strategically written in autoloaded
-spots.
-
-### When Constants aren't Missed
-
-#### Relative References
-
-Let's consider a flight simulator. The application has a default flight model
-
-```ruby
-# app/models/flight_model.rb
-class FlightModel
-end
-```
-
-that can be overridden by each airplane, for instance
-
-```ruby
-# app/models/bell_x1/flight_model.rb
-module BellX1
- class FlightModel < FlightModel
- end
-end
-
-# app/models/bell_x1/aircraft.rb
-module BellX1
- class Aircraft
- def initialize
- @flight_model = FlightModel.new
- end
- end
-end
-```
-
-The initializer wants to create a `BellX1::FlightModel` and nesting has
-`BellX1`, that looks good. But if the default flight model is loaded and the
-one for the Bell-X1 is not, the interpreter is able to resolve the top-level
-`FlightModel` and autoloading is thus not triggered for `BellX1::FlightModel`.
-
-That code depends on the execution path.
-
-These kind of ambiguities can often be resolved using qualified constants:
-
-```ruby
-module BellX1
- class Plane
- def flight_model
- @flight_model ||= BellX1::FlightModel.new
- end
- end
-end
-```
-
-Also, `require_dependency` is a solution:
-
-```ruby
-require_dependency 'bell_x1/flight_model'
-
-module BellX1
- class Plane
- def flight_model
- @flight_model ||= FlightModel.new
- end
- end
-end
-```
-
-#### Qualified References
-
-Given
-
-```ruby
-# app/models/hotel.rb
-class Hotel
-end
-
-# app/models/image.rb
-class Image
-end
-
-# app/models/hotel/image.rb
-class Hotel
- class Image < Image
- end
-end
-```
-
-the expression `Hotel::Image` is ambiguous, depends on the execution path.
-
-As [we saw before](#resolution-algorithm-for-qualified-constants), Ruby looks
-up the constant in `Hotel` and its ancestors. If `app/models/image.rb` has
-been loaded but `app/models/hotel/image.rb` hasn't, Ruby does not find `Image`
-in `Hotel`, but it does in `Object`:
-
-```
-$ bin/rails r 'Image; p Hotel::Image' 2>/dev/null
-Image # NOT Hotel::Image!
-```
-
-The code evaluating `Hotel::Image` needs to make sure
-`app/models/hotel/image.rb` has been loaded, possibly with
-`require_dependency`.
-
-In these cases the interpreter issues a warning though:
-
-```
-warning: toplevel constant Image referenced by Hotel::Image
-```
-
-This surprising constant resolution can be observed with any qualifying class:
-
-```
-2.1.5 :001 > String::Array
-(irb):1: warning: toplevel constant Array referenced by String::Array
- => Array
-```
-
-WARNING. To find this gotcha the qualifying namespace has to be a class,
-`Object` is not an ancestor of modules.
-
-### Autoloading within Singleton Classes
-
-Let's suppose we have these class definitions:
-
-```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
-```
-
-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.
-
-But if `Hotel::Services` is not known, Rails is not able to autoload it, the
-application raises `NameError`.
-
-The reason is that autoloading is triggered for the singleton class, which is
-anonymous, and as [we saw before](#generic-procedure), Rails only checks the
-top-level namespace in that edge case.
-
-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`:
-
-```ruby
-c = C.new
-c.user # surprisingly fine, User
-c.user # NameError: uninitialized constant C::User
-```
-
-because it detects a parent namespace already has the constant (see [Qualified
-References](#qualified-references).)
-
-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
-```