提交 57689218 编写于 作者: X Xavier Noria

documents autoloading in the upgrading guide [ci skip]

上级 d0a74604
......@@ -133,6 +133,178 @@ Action Cable JavaScript API:
+ ActionCable.logger.enabled = false
```
### Autoloading
The default configuration for Rails 6
```ruby
# config/application.rb
load_defaults "6.0"
```
enables `zeitwerk` autoloading mode on CRuby. In that mode, autoloading, reloading, and eager loading are managed by [Zeitwerk](https://github.com/fxn/zeitwerk).
#### Public API
In general, applications do not need to use the API of Zeitwerk directly. Rails sets things up according to the existing contract: `config.autoload_paths`, `config.cache_classes`, etc.
While applications should stick to that interface, the actual Zeitwerk loader object can be accessed as
```ruby
Rails.autoloaders.main
```
That may be handy if you need to preload STIs or configure a custom inflector, for example.
#### Project Structure
If the application being upgraded autoloads correctly, the project structure should be already mostly compatible.
However, `classic` mode infers file names from missing constant names (`underscore`), whereas `zeitwerk` mode infers constant names from file names (`camelize`). These helpers are not always inverse of each other, in particular if acronyms are involved. For instance, `"FOO".underscore` is `"foo"`, but `"foo".camelize` is `"Foo"`, not `"FOO"`. Compatibility can be checked by setting `classic` mode first temporarily:
```ruby
# config/application.rb
load_defaults "6.0"
config.autoloader = :classic
```
and then running
```
bin/rails zeitwerk:check
```
When all is good, you can delete `config.autoloader = :classic`.
#### require_dependency
All known use cases of `require_dependency` have been eliminated, you should grep the project and delete them.
In the case of STIs with a hierarchy of more than two levels, you can preload the leaves of the hierarchy in an initializer:
```ruby
# config/initializers/preload_stis.rb
# By preloading leaves, the entire hierarchy is loaded upwards following
# the references to superclasses in the class definitions.
sti_leaves = %w(
app/models/leaf1.rb
app/models/leaf2.rb
app/models/leaf3.rb
)
Rails.autoloaders.main.preload(sti_leaves)
```
#### Qualified names in class and module definitions
You can now robustly use constant paths in class and module definitions:
```ruby
# Autoloading in this class' body matches Ruby semantics now.
class Admin::UsersController < ApplicationController
# ...
end
```
A gotcha to be aware of is that, depending on the order of execution, the classic autoloader could sometimes be able to autoload `Foo::Wadus` in
```ruby
class Foo::Bar
Wadus
end
```
That does not match Ruby semantics because `Foo` is not in the nesting, and won't work at all in `zeitwerk` mode. If you find such corner case you can use the qualified name `Foo::Wadus`:
```ruby
class Foo::Bar
Foo::Wadus
end
```
or add `Foo` to the nesting:
```ruby
module Foo
class Bar
Wadus
end
end
```
#### Concerns
You can autoload and eager load from a standard structure like
```
app/models
app/models/concerns
```
In that case, `app/models/concerns` is assumed to be a root directory (because it belongs to the autoload paths), and it is ignored as namespace. So, `app/models/concerns/foo.rb` should define `Foo`, not `Concerns::Foo`.
The `Concerns::` namespace worked with the classic autoloader as a side-effect of the implementation, but it was not really an intended behavior. An application using `Concerns::` needs to rename those classes and modules to be able to run in `zeitwerk` mode.
#### Spring and the `test` Environment
Spring reloads the application code if something changes. In the `test` environment you need to enable reloading for that to work:
```ruby
# config/environments/test.rb
config.cache_classes = false
```
Otherwise you'll get this error:
```
reloading is disabled because config.cache_classes is true
```
#### Bootsnap
Bootsnap should be at least version 1.4.2.
In addition to that, Bootsnap needs to disable the iseq cache due to a bug in the interpreter if running Ruby 2.5. Please make sure to depend on at least Bootsnap 1.4.4 in that case.
#### `config.add_autoload_paths_to_load_path`
The new configuration point
```ruby
config.add_autoload_paths_to_load_path
```
is `true` by default for backwards compatibility, but allows you to opt-out from adding the autoload paths to `$LOAD_PATH`.
This makes sense in most applications, since you never should require a file in `app/models`, for example, and Zeitwerk only uses absolute file names internally.
By opting-out you optimize `$LOAD_PATH` lookups (less directories to check), and save Bootsnap work and memory consumption, since it does not need to build an index for these directories.
#### Thread-safety
In classic mode constant autoloading is not thread-safe, though Rails has locks in place for example to make web requests thread-safe when autoloading is enabled, as it is common in `development` mode.
Constant autoloading is thread-safe in `zeitwerk` mode. For example, you can now autoload in multi-threaded scripts executed by the `runner` command.
#### Globs in config.autoload_paths
Beware of configurations like
```ruby
config.autoload_paths += Dir["#{config.root}/lib/**/"]
```
Every element of `config.autoload_paths` should represent the top-level namespace (`Object`) and they cannot be nested in consequence (with the exception of `concerns` directories explained above).
To fix this, just remove the wildcards:
```ruby
config.autoload_paths << "#{config.root}/lib"
```
Upgrading from Rails 5.1 to Rails 5.2
-------------------------------------
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册