Define config.enable_reloading to be !config.cache_classes

Every time I write `config.cache_classes` I have to pause for a moment to make
sure I get it right. It makes you think.

On the other hand, if you read `config.enable_reloading = true`, does the
application reload? You do not need to spend 1 cycle of brain CPU to nod.
This commit is contained in:
Xavier Noria 2022-04-14 18:11:36 +02:00
parent 51b4370bb3
commit 2953ae5c8a
35 changed files with 181 additions and 120 deletions

@ -6,7 +6,7 @@
# In the development environment your application's code is reloaded any time # In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development # it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes. # since you don't have to restart the web server when you make code changes.
config.cache_classes = false config.enable_reloading = true
# Do not eager load code on boot. # Do not eager load code on boot.
config.eager_load = false config.eager_load = false

@ -2,7 +2,7 @@
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests. # Code is not reloaded between requests.
config.cache_classes = true config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and # Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers # your application in memory, allowing both threaded web servers

@ -5,7 +5,7 @@
# test suite. You never need to work with it otherwise. Remember that # test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped # your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there! # and recreated between test runs. Don't rely on the data there!
config.cache_classes = true config.enable_reloading = false
# Do not eager load code on boot. This avoids loading your whole application # Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that # just for the purpose of running a single test. If you are using a tool that

@ -1,12 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
module ActionDispatch module ActionDispatch
# ActionDispatch::Reloader wraps the request with callbacks provided by ActiveSupport::Reloader # ActionDispatch::Reloader wraps the request with callbacks provided by
# callbacks, intended to assist with code reloading during development. # ActiveSupport::Reloader, intended to assist with code reloading during
# development.
# #
# By default, ActionDispatch::Reloader is included in the middleware stack # ActionDispatch::Reloader is included in the middleware stack only if
# only in the development environment; specifically, when +config.cache_classes+ # reloading is enabled, which it is by the default in +development+ mode.
# is false.
class Reloader < Executor class Reloader < Executor
end end
end end

@ -6,7 +6,7 @@
# In the development environment your application's code is reloaded any time # In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development # it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes. # since you don't have to restart the web server when you make code changes.
config.cache_classes = false config.enable_reloading = true
# Do not eager load code on boot. # Do not eager load code on boot.
config.eager_load = false config.eager_load = false

@ -4,7 +4,7 @@
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests. # Code is not reloaded between requests.
config.cache_classes = true config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and # Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers # your application in memory, allowing both threaded web servers

@ -5,7 +5,7 @@
# test suite. You never need to work with it otherwise. Remember that # test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped # your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there! # and recreated between test runs. Don't rely on the data there!
config.cache_classes = true config.enable_reloading = false
# Do not eager load code on boot. This avoids loading your whole application # Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that # just for the purpose of running a single test. If you are using a tool that

@ -74,7 +74,7 @@ class Railtie < Rails::Engine # :nodoc:
initializer "action_view.caching" do |app| initializer "action_view.caching" do |app|
ActiveSupport.on_load(:action_view) do ActiveSupport.on_load(:action_view) do
if app.config.action_view.cache_template_loading.nil? if app.config.action_view.cache_template_loading.nil?
ActionView::Resolver.caching = app.config.cache_classes ActionView::Resolver.caching = !app.config.reloading_enabled?
end end
end end
end end
@ -91,7 +91,7 @@ class Railtie < Rails::Engine # :nodoc:
config.after_initialize do |app| config.after_initialize do |app|
enable_caching = if app.config.action_view.cache_template_loading.nil? enable_caching = if app.config.action_view.cache_template_loading.nil?
app.config.cache_classes !app.config.reloading_enabled?
else else
app.config.action_view.cache_template_loading app.config.action_view.cache_template_loading
end end

@ -16,7 +16,7 @@ class Server < Rails::Application
get "/error" => proc { |env| [403, {}, []] } get "/error" => proc { |env| [403, {}, []] }
end end
config.cache_classes = false config.enable_reloading = true
config.eager_load = false config.eager_load = false
config.secret_key_base = "59d7a4dbd349fa3838d79e330e39690fc22b931e7dc17d9162f03d633d526fbb92dfdb2dc9804c8be3e199631b9c1fbe43fc3e4fc75730b515851849c728d5c7" config.secret_key_base = "59d7a4dbd349fa3838d79e330e39690fc22b931e7dc17d9162f03d633d526fbb92dfdb2dc9804c8be3e199631b9c1fbe43fc3e4fc75730b515851849c728d5c7"
config.paths["app/views"].unshift("#{Rails.root}/views") config.paths["app/views"].unshift("#{Rails.root}/views")

@ -389,7 +389,7 @@ class Railtie < Rails::Railtie # :nodoc:
initializer "active_record.unregister_current_scopes_on_unload" do |app| initializer "active_record.unregister_current_scopes_on_unload" do |app|
config.after_initialize do config.after_initialize do
unless app.config.cache_classes if app.config.reloading_enabled?
Rails.autoloaders.main.on_unload do |_cpath, value, _abspath| Rails.autoloaders.main.on_unload do |_cpath, value, _abspath|
# Conditions are written this way to be robust against custom # Conditions are written this way to be robust against custom
# implementations of value#is_a? or value#<. # implementations of value#is_a? or value#<.

@ -6,7 +6,7 @@
# In the development environment your application's code is reloaded any time # In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development # it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes. # since you don't have to restart the web server when you make code changes.
config.cache_classes = false config.enable_reloading = true
# Do not eager load code on boot. # Do not eager load code on boot.
config.eager_load = false config.eager_load = false

@ -4,7 +4,7 @@
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests. # Code is not reloaded between requests.
config.cache_classes = true config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and # Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers # your application in memory, allowing both threaded web servers

@ -7,7 +7,7 @@
# test suite. You never need to work with it otherwise. Remember that # test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped # your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there! # and recreated between test runs. Don't rely on the data there!
config.cache_classes = true config.enable_reloading = false
# Do not eager load code on boot. This avoids loading your whole application # Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that # just for the purpose of running a single test. If you are using a tool that

@ -64,7 +64,7 @@ def descendants(klass)
end end
def clear(classes) # :nodoc: def clear(classes) # :nodoc:
raise "DescendantsTracker.clear was disabled because config.cache_classes = true" if @clear_disabled raise "DescendantsTracker.clear was disabled because config.enable_reloading is false" if @clear_disabled
classes.each do |klass| classes.each do |klass|
@@excluded_descendants[klass] = true @@excluded_descendants[klass] = true
@ -116,7 +116,7 @@ def descendants(klass)
end end
def clear(classes) # :nodoc: def clear(classes) # :nodoc:
raise "DescendantsTracker.clear was disabled because config.cache_classes = true" if @clear_disabled raise "DescendantsTracker.clear was disabled because config.enable_reloading is false" if @clear_disabled
@@direct_descendants.each do |klass, direct_descendants_of_klass| @@direct_descendants.each do |klass, direct_descendants_of_klass|
if classes.member?(klass) if classes.member?(klass)

@ -60,7 +60,7 @@ def self.initialize_i18n(app)
# Restore available locales check so it will take place from now on. # Restore available locales check so it will take place from now on.
I18n.enforce_available_locales = enforce_available_locales I18n.enforce_available_locales = enforce_available_locales
unless app.config.cache_classes if app.config.reloading_enabled?
directories = watched_dirs_with_extensions(reloadable_paths) directories = watched_dirs_with_extensions(reloadable_paths)
reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
I18n.load_path.keep_if { |p| File.exist?(p) } I18n.load_path.keep_if { |p| File.exist?(p) }

@ -174,11 +174,11 @@ Rails automatically reloads classes and modules if application files in the auto
More precisely, if the web server is running and application files have been modified, Rails unloads all autoloaded constants managed by the `main` autoloader just before the next request is processed. That way, application classes or modules used during that request will be autoloaded again, thus picking up their current implementation in the file system. More precisely, if the web server is running and application files have been modified, Rails unloads all autoloaded constants managed by the `main` autoloader just before the next request is processed. That way, application classes or modules used during that request will be autoloaded again, thus picking up their current implementation in the file system.
Reloading can be enabled or disabled. The setting that controls this behavior is [`config.cache_classes`][], which is false by default in `development` mode (reloading enabled), and true by default in `production` mode (reloading disabled). Reloading can be enabled or disabled. The setting that controls this behavior is [`config.enable_reloading`][], which is `true` by default in `development` mode, and `false` by default in `production` mode. For backwards compatibility, Rails also supports `config.cache_classes`, which is equivalent to `!config.enable_reloading`.
Rails uses an evented file monitor to detect files changes by default. It can be configured instead to detect file changes by walking the autoload paths. This is controlled by the [`config.file_watcher`][] setting. Rails uses an evented file monitor to detect files changes by default. It can be configured instead to detect file changes by walking the autoload paths. This is controlled by the [`config.file_watcher`][] setting.
In a Rails console there is no file watcher active regardless of the value of `config.cache_classes`. This is because, normally, it would be confusing to have code reloaded in the middle of a console session. Similar to an individual request, you generally want a console session to be served by a consistent, non-changing set of application classes and modules. In a Rails console there is no file watcher active regardless of the value of `config.enable_reloading`. This is because, normally, it would be confusing to have code reloaded in the middle of a console session. Similar to an individual request, you generally want a console session to be served by a consistent, non-changing set of application classes and modules.
However, you can force a reload in the console by executing `reload!`: However, you can force a reload in the console by executing `reload!`:
@ -194,7 +194,7 @@ irb(main):003:0> User.object_id
As you can see, the class object stored in the `User` constant is different after reloading. As you can see, the class object stored in the `User` constant is different after reloading.
[`config.cache_classes`]: configuring.html#config-cache-classes [`config.enable_reloading`]: configuring.html#config-enable-reloading
[`config.file_watcher`]: configuring.html#config-file-watcher [`config.file_watcher`]: configuring.html#config-file-watcher
### Reloading and Stale Objects ### Reloading and Stale Objects

@ -362,7 +362,7 @@ as
```ruby ```ruby
# config/initializers/country.rb # config/initializers/country.rb
unless Rails.application.config.cache_classes if Rails.application.config.reloading_enabled?
Rails.autoloaders.main.on_unload("Country") do |klass, _abspath| Rails.autoloaders.main.on_unload("Country") do |klass, _abspath|
klass.expire_redis_cache klass.expire_redis_cache
end end
@ -378,12 +378,25 @@ Spring reloads the application code if something changes. In the `test` environm
config.cache_classes = false config.cache_classes = false
``` ```
Otherwise you'll get this error: or, since Rails 7.1:
```ruby
# config/environments/test.rb
config.enable_reloading = true
```
Otherwise, you'll get:
``` ```
reloading is disabled because config.cache_classes is true reloading is disabled because config.cache_classes is true
``` ```
or
```
reloading is disabled because config.enable_reloading is false
```
This has no performance penalty. This has no performance penalty.
### Bootsnap ### Bootsnap

@ -160,7 +160,7 @@ Sets the host for the assets. Useful when CDNs are used for hosting assets, or w
#### `config.autoload_once_paths` #### `config.autoload_once_paths`
Accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if `config.cache_classes` is `false`, which is the default in the development environment. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array. Accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if reloading is enabled, which it is by default in the `development` environment. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array.
#### `config.autoload_paths` #### `config.autoload_paths`
@ -177,9 +177,15 @@ The default value depends on the `config.load_defaults` target version:
| (original) | `true` | | (original) | `true` |
| 7.1 | `false` | | 7.1 | `false` |
#### `config.enable_reloading`
If `config.enable_reloading` is true, application classes and modules are reloaded in between web requests if they change. Defaults to `true` in the `development` environment, and `false` in the `production` environment.
The predicate `config.reloading_enabled?` is also defined.
#### `config.cache_classes` #### `config.cache_classes`
Controls whether or not application classes and modules should be reloaded if they change. When the cache is enabled (`true`), reloading will not occur. Defaults to `false` in the development environment, and `true` in production. In the test environment, the default is `false` if Spring is installed, `true` otherwise. Old setting equivalent to `!config.enable_reloading`. Supported for backwards compatibility.
#### `config.beginning_of_week` #### `config.beginning_of_week`
@ -225,11 +231,11 @@ Registers namespaces that are eager loaded when `config.eager_load` is set to `t
#### `config.eager_load_paths` #### `config.eager_load_paths`
Accepts an array of paths from which Rails will eager load on boot if `config.cache_classes` is set to `true`. Defaults to every folder in the `app` directory of the application. Accepts an array of paths from which Rails will eager load on boot if `config.eager_load` is true. Defaults to every folder in the `app` directory of the application.
#### `config.enable_dependency_loading` #### `config.enable_dependency_loading`
When `true`, enables autoloading, even if the application is eager loaded and `config.cache_classes` is set to `true`. Defaults to `false`. When `true`, enables autoloading, even if the application is eager loaded and `config.enable_reloading` is set to `false`. Defaults to `false`.
#### `config.encoding` #### `config.encoding`
@ -311,7 +317,7 @@ When `true`, eager load the application when running Rake tasks. Defaults to `fa
#### `config.reload_classes_only_on_change` #### `config.reload_classes_only_on_change`
Enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to `true`. If `config.cache_classes` is `true`, this option is ignored. Enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to `true`. If `config.enable_reloading` is `false`, this option is ignored.
#### `config.credentials.content_path` #### `config.credentials.content_path`
@ -1383,7 +1389,7 @@ Takes a block of code to run after the request.
#### `config.action_view.cache_template_loading` #### `config.action_view.cache_template_loading`
Controls whether or not templates should be reloaded on each request. Defaults to whatever is set for `config.cache_classes`. Controls whether or not templates should be reloaded on each request. Defaults to `!config.enable_reloading`.
#### `config.action_view.field_error_proc` #### `config.action_view.field_error_proc`
@ -2730,7 +2736,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde
* `initialize_cache`: If `Rails.cache` isn't set yet, initializes the cache by referencing the value in `config.cache_store` and stores the outcome as `Rails.cache`. If this object responds to the `middleware` method, its middleware is inserted before `Rack::Runtime` in the middleware stack. * `initialize_cache`: If `Rails.cache` isn't set yet, initializes the cache by referencing the value in `config.cache_store` and stores the outcome as `Rails.cache`. If this object responds to the `middleware` method, its middleware is inserted before `Rack::Runtime` in the middleware stack.
* `set_clear_dependencies_hook`: This initializer - which runs only if `cache_classes` is set to `false` - uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request. * `set_clear_dependencies_hook`: This initializer - which runs only if `config.enable_reloading` is set to `true` - uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request.
* `bootstrap_hook`: Runs all configured `before_initialize` blocks. * `bootstrap_hook`: Runs all configured `before_initialize` blocks.
@ -2774,7 +2780,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde
* `active_record.log_runtime`: Includes `ActiveRecord::Railties::ControllerRuntime` which is responsible for reporting the time taken by Active Record calls for the request back to the logger. * `active_record.log_runtime`: Includes `ActiveRecord::Railties::ControllerRuntime` which is responsible for reporting the time taken by Active Record calls for the request back to the logger.
* `active_record.set_reloader_hooks`: Resets all reloadable connections to the database if `config.cache_classes` is set to `false`. * `active_record.set_reloader_hooks`: Resets all reloadable connections to the database if `config.enable_reloading` is set to `true`.
* `active_record.add_watchable_files`: Adds `schema.rb` and `structure.sql` files to watchable files. * `active_record.add_watchable_files`: Adds `schema.rb` and `structure.sql` files to watchable files.
@ -2956,8 +2962,7 @@ Evented File System Monitor
--------------------------- ---------------------------
If the [listen gem](https://github.com/guard/listen) is loaded Rails uses an If the [listen gem](https://github.com/guard/listen) is loaded Rails uses an
evented file system monitor to detect changes when `config.cache_classes` is evented file system monitor to detect changes when reloading is enabled:
`false`:
```ruby ```ruby
group :development do group :development do

@ -200,18 +200,19 @@ additional threads.
### Configuration ### Configuration
The Reloader only checks for file changes when `cache_classes` is false and The Reloader only checks for file changes when `config.enable_reloading` is
`reload_classes_only_on_change` is true (which is the default in the `true` and so is `config.reload_classes_only_on_change`. These are the defaults in the
`development` environment). `development` environment.
When `cache_classes` is true (in `production`, by default), the Reloader is only When `config.enable_reloading` is `false` (in `production`, by default), the
a pass-through to the Executor. Reloader is only a pass-through to the Executor.
The Executor always has important work to do, like database connection The Executor always has important work to do, like database connection
management. When `cache_classes` and `eager_load` are both true (`production`), management. When `config.enable_reloading` is `false` and `config.eager_load` is
no autoloading or class reloading will occur, so it does not need the Load `true` (`production` defaults), no reloading will occur, so it does not need the
Interlock. If either of those are false (`development`), then the Executor will Load Interlock. With the default settings in the `development` environment, the
use the Load Interlock to ensure constants are only loaded when it is safe. Executor will use the Load Interlock to ensure constants are only loaded when it
is safe.
Load Interlock Load Interlock
-------------- --------------

@ -1,3 +1,7 @@
* Define `config.enable_reloading` to be `!config.cache_classes` for a more intuitive name. While `config.enable_reloading` and `config.reloading_enabled?` are preferred from now on, `config.cache_classes` is supported for backwards compatibility.
*Xavier Noria*
* Add JavaScript dependencies installation on bin/setup * Add JavaScript dependencies installation on bin/setup
Add `yarn install` to bin/setup when using esbuild, webpack, or rollout. Add `yarn install` to bin/setup when using esbuild, webpack, or rollout.

@ -26,7 +26,7 @@ module Rails
# #
# Besides providing the same configuration as Rails::Engine and Rails::Railtie, # Besides providing the same configuration as Rails::Engine and Rails::Railtie,
# the application object has several specific configurations, for example # the application object has several specific configurations, for example
# +cache_classes+, +consider_all_requests_local+, +filter_parameters+, # +enable_reloading+, +consider_all_requests_local+, +filter_parameters+,
# +logger+, and so forth. # +logger+, and so forth.
# #
# Check Rails::Application::Configuration to see them all. # Check Rails::Application::Configuration to see them all.

@ -28,7 +28,7 @@ module Bootstrap
* production - set it to true * production - set it to true
INFO INFO
config.eager_load = config.cache_classes config.eager_load = !config.reloading_enabled?
end end
end end

@ -285,6 +285,18 @@ def load_defaults(target_version)
@loaded_config_version = target_version @loaded_config_version = target_version
end end
def reloading_enabled?
enable_reloading
end
def enable_reloading
!cache_classes
end
def enable_reloading=(value)
self.cache_classes = !value
end
def encoding=(value) def encoding=(value)
@encoding = value @encoding = value
silence_warnings do silence_warnings do

@ -56,7 +56,7 @@ def build_stack
middleware.use ::ActionDispatch::ActionableExceptions middleware.use ::ActionDispatch::ActionableExceptions
end end
unless config.cache_classes if config.reloading_enabled?
middleware.use ::ActionDispatch::Reloader, app.reloader middleware.use ::ActionDispatch::Reloader, app.reloader
end end

@ -26,7 +26,7 @@ module Finisher
autoloader.do_not_eager_load(path) unless ActiveSupport::Dependencies.eager_load?(path) autoloader.do_not_eager_load(path) unless ActiveSupport::Dependencies.eager_load?(path)
end end
unless config.cache_classes if config.reloading_enabled?
autoloader.enable_reloading autoloader.enable_reloading
ActiveSupport::Dependencies.autoloader = autoloader ActiveSupport::Dependencies.autoloader = autoloader
@ -74,7 +74,7 @@ module Finisher
Zeitwerk::Loader.eager_load_all Zeitwerk::Loader.eager_load_all
config.eager_load_namespaces.each(&:eager_load!) config.eager_load_namespaces.each(&:eager_load!)
unless config.cache_classes if config.reloading_enabled?
app.reloader.after_class_unload do app.reloader.after_class_unload do
Rails.autoloaders.main.eager_load Rails.autoloaders.main.eager_load
end end
@ -125,10 +125,7 @@ def self.complete(_state)
else else
# Default concurrency setting: enabled, but safe # Default concurrency setting: enabled, but safe
unless config.cache_classes && config.eager_load if config.reloading_enabled? || !config.eager_load
# Without cache_classes + eager_load, the load interlock
# is required for proper operation
app.executor.register_hook(InterlockHook, outer: true) app.executor.register_hook(InterlockHook, outer: true)
end end
end end
@ -181,39 +178,42 @@ def self.complete(_state)
ActiveSupport::Dependencies.clear ActiveSupport::Dependencies.clear
end end
if config.cache_classes if config.reloading_enabled?
app.reloader.check = lambda { false } if config.reload_classes_only_on_change
elsif config.reload_classes_only_on_change app.reloader.check = lambda do
app.reloader.check = lambda do app.reloaders.map(&:updated?).any?
app.reloaders.map(&:updated?).any? end
else
app.reloader.check = lambda { true }
end end
else else
app.reloader.check = lambda { true } app.reloader.check = lambda { false }
end end
if config.cache_classes if config.reloading_enabled?
# No reloader if config.reload_classes_only_on_change
ActiveSupport::DescendantsTracker.disable_clear! reloader = config.file_watcher.new(*watchable_args, &callback)
elsif config.reload_classes_only_on_change reloaders << reloader
reloader = config.file_watcher.new(*watchable_args, &callback)
reloaders << reloader
# Prepend this callback to have autoloaded constants cleared before # Prepend this callback to have autoloaded constants cleared before
# any other possible reloading, in case they need to autoload fresh # any other possible reloading, in case they need to autoload fresh
# constants. # constants.
app.reloader.to_run(prepend: true) do app.reloader.to_run(prepend: true) do
# In addition to changes detected by the file watcher, if routes # In addition to changes detected by the file watcher, if routes
# or i18n have been updated we also need to clear constants, # or i18n have been updated we also need to clear constants,
# that's why we run #execute rather than #execute_if_updated, this # that's why we run #execute rather than #execute_if_updated, this
# callback has to clear autoloaded constants after any update. # callback has to clear autoloaded constants after any update.
class_unload! do class_unload! do
reloader.execute reloader.execute
end
end
else
app.reloader.to_complete do
class_unload!(&callback)
end end
end end
else else
app.reloader.to_complete do ActiveSupport::DescendantsTracker.disable_clear!
class_unload!(&callback)
end
end end
end end
end end

@ -6,7 +6,7 @@ Rails.application.configure do
# In the development environment your application's code is reloaded any time # In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development # it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes. # since you don't have to restart the web server when you make code changes.
config.cache_classes = false config.enable_reloading = true
# Do not eager load code on boot. # Do not eager load code on boot.
config.eager_load = false config.eager_load = false

@ -4,7 +4,7 @@ Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests. # Code is not reloaded between requests.
config.cache_classes = true config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and # Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers # your application in memory, allowing both threaded web servers

@ -8,8 +8,8 @@ require "active_support/core_ext/integer/time"
Rails.application.configure do Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# Turn false under Spring and add config.action_view.cache_template_loading = true. # Turn true under Spring and add config.action_view.cache_template_loading = true.
config.cache_classes = true config.enable_reloading = false
# Eager loading loads your whole application. When running a single test locally, # Eager loading loads your whole application. When running a single test locally,
# this probably isn't necessary. It's a good idea to do in a continuous integration # this probably isn't necessary. It's a good idea to do in a continuous integration

@ -291,6 +291,28 @@ def change
assert_instance_of Pathname, Rails.public_path assert_instance_of Pathname, Rails.public_path
end end
test "config.enable_reloading is !config.cache_classes" do
app "development"
config = Rails.application.config
assert_equal !config.cache_classes, config.enable_reloading
[true, false].each do |enabled|
config.enable_reloading = enabled
assert_equal enabled, config.enable_reloading
assert_equal enabled, config.reloading_enabled?
assert_equal enabled, !config.cache_classes
end
[true, false].each do |enabled|
config.cache_classes = enabled
assert_equal enabled, !config.enable_reloading
assert_equal enabled, !config.reloading_enabled?
assert_equal enabled, config.cache_classes
end
end
test "does not eager load controllers state actions in development" do test "does not eager load controllers state actions in development" do
app_file "app/controllers/posts_controller.rb", <<-RUBY app_file "app/controllers/posts_controller.rb", <<-RUBY
class PostsController < ActionController::Base class PostsController < ActionController::Base
@ -314,8 +336,8 @@ def show;end
RUBY RUBY
add_to_config <<-RUBY add_to_config <<-RUBY
config.enable_reloading = false
config.eager_load = true config.eager_load = true
config.cache_classes = true
RUBY RUBY
app "production" app "production"
@ -344,8 +366,8 @@ def noop_email;end
RUBY RUBY
add_to_config <<-RUBY add_to_config <<-RUBY
config.enable_reloading = false
config.eager_load = true config.eager_load = true
config.cache_classes = true
RUBY RUBY
app "production" app "production"
@ -391,8 +413,8 @@ class Post < ActiveRecord::Base
RUBY RUBY
add_to_config <<-RUBY add_to_config <<-RUBY
config.enable_reloading = false
config.eager_load = true config.eager_load = true
config.cache_classes = true
RUBY RUBY
app "production" app "production"
@ -417,8 +439,8 @@ class Post < ActiveRecord::Base
RUBY RUBY
add_to_config <<-RUBY add_to_config <<-RUBY
config.enable_reloading = false
config.eager_load = true config.eager_load = true
config.cache_classes = true
RUBY RUBY
app_file "config/initializers/schema_cache.rb", <<-RUBY app_file "config/initializers/schema_cache.rb", <<-RUBY
@ -447,8 +469,8 @@ class Post < ActiveRecord::Base
RUBY RUBY
add_to_config <<-RUBY add_to_config <<-RUBY
config.enable_reloading = false
config.eager_load = true config.eager_load = true
config.cache_classes = true
RUBY RUBY
app_file "app/models/comment.rb", <<-RUBY app_file "app/models/comment.rb", <<-RUBY
@ -473,8 +495,8 @@ class Comment < ActiveRecord::Base
FileUtils.rm_rf("#{app_path}/app/mailers/application_mailer.rb") FileUtils.rm_rf("#{app_path}/app/mailers/application_mailer.rb")
FileUtils.rm_rf("#{app_path}/config/environments") FileUtils.rm_rf("#{app_path}/config/environments")
add_to_config <<-RUBY add_to_config <<-RUBY
config.enable_reloading = false
config.eager_load = true config.eager_load = true
config.cache_classes = true
RUBY RUBY
use_frameworks [] use_frameworks []
@ -1265,8 +1287,8 @@ def index
assert_equal Rails::Autoloaders::Inflector, Rails.autoloaders.once.inflector assert_equal Rails::Autoloaders::Inflector, Rails.autoloaders.once.inflector
end end
test "config.action_view.cache_template_loading with cache_classes default" do test "config.action_view.cache_template_loading with config.enable_reloading default" do
add_to_config "config.cache_classes = true" add_to_config "config.enable_reloading = false"
app "development" app "development"
require "action_view/base" require "action_view/base"
@ -1274,8 +1296,8 @@ def index
assert_equal true, ActionView::Resolver.caching? assert_equal true, ActionView::Resolver.caching?
end end
test "config.action_view.cache_template_loading without cache_classes default" do test "config.action_view.cache_template_loading without config.enable_reloading default" do
add_to_config "config.cache_classes = false" add_to_config "config.enable_reloading = true"
app "development" app "development"
require "action_view/base" require "action_view/base"
@ -1285,7 +1307,7 @@ def index
test "config.action_view.cache_template_loading = false" do test "config.action_view.cache_template_loading = false" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = true config.enable_reloading = false
config.action_view.cache_template_loading = false config.action_view.cache_template_loading = false
RUBY RUBY
@ -1297,7 +1319,7 @@ def index
test "config.action_view.cache_template_loading = true" do test "config.action_view.cache_template_loading = true" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
config.action_view.cache_template_loading = true config.action_view.cache_template_loading = true
RUBY RUBY
@ -1307,9 +1329,9 @@ def index
assert_equal true, ActionView::Resolver.caching? assert_equal true, ActionView::Resolver.caching?
end end
test "config.action_view.cache_template_loading with cache_classes in an environment" do test "config.action_view.cache_template_loading with config.enable_reloading in an environment" do
build_app(initializers: true) build_app(initializers: true)
add_to_env_config "development", "config.cache_classes = false" add_to_env_config "development", "config.enable_reloading = true"
# These requires are to emulate an engine loading Action View before the application # These requires are to emulate an engine loading Action View before the application
require "action_view" require "action_view"

@ -64,7 +64,7 @@ def teardown
test "after_initialize happens after to_prepare in development" do test "after_initialize happens after to_prepare in development" do
$order = [] $order = []
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
config.after_initialize { $order << :after_initialize } config.after_initialize { $order << :after_initialize }
config.to_prepare { $order << :to_prepare } config.to_prepare { $order << :to_prepare }
RUBY RUBY
@ -76,7 +76,7 @@ def teardown
test "after_initialize happens after to_prepare in production" do test "after_initialize happens after to_prepare in production" do
$order = [] $order = []
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = true config.enable_reloading = false
config.after_initialize { $order << :after_initialize } config.after_initialize { $order << :after_initialize }
config.to_prepare { $order << :to_prepare } config.to_prepare { $order << :to_prepare }
RUBY RUBY

@ -70,7 +70,7 @@ def assert_no_fallbacks
test "load_path is populated before eager loaded models" do test "load_path is populated before eager loaded models" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = true config.enable_reloading = false
RUBY RUBY
app_file "config/locales/en.yml", <<-YAML app_file "config/locales/en.yml", <<-YAML
@ -100,7 +100,7 @@ class Foo < ActiveRecord::Base
test "locales are reloaded if they change between requests" do test "locales are reloaded if they change between requests" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/locales/en.yml", <<-YAML app_file "config/locales/en.yml", <<-YAML
@ -135,7 +135,7 @@ class Foo < ActiveRecord::Base
test "new locale files are loaded" do test "new locale files are loaded" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/locales/en.yml", <<-YAML app_file "config/locales/en.yml", <<-YAML
@ -171,7 +171,7 @@ class Foo < ActiveRecord::Base
test "I18n.load_path is reloaded" do test "I18n.load_path is reloaded" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/locales/en.yml", <<-YAML app_file "config/locales/en.yml", <<-YAML

@ -91,7 +91,7 @@ module Foo; end
app_file "config/environments/development.rb", <<-RUBY app_file "config/environments/development.rb", <<-RUBY
$initialize_test_set_from_env = 'success' $initialize_test_set_from_env = 'success'
Rails.application.configure do Rails.application.configure do
config.cache_classes = true config.enable_reloading = false
config.time_zone = "Brasilia" config.time_zone = "Brasilia"
end end
RUBY RUBY
@ -104,7 +104,7 @@ module Foo; end
require "#{app_path}/config/environment" require "#{app_path}/config/environment"
assert_equal "success", $initialize_test_set_from_env assert_equal "success", $initialize_test_set_from_env
assert Rails.application.config.cache_classes assert_not Rails.application.config.reloading_enabled?
assert_equal "Brasilia", Rails.application.config.time_zone assert_equal "Brasilia", Rails.application.config.time_zone
end end
end end

@ -109,9 +109,9 @@ class User < ActiveRecord::Base
assert ::Rails.application.config.loaded assert ::Rails.application.config.loaded
end end
test "descendants loaded after framework initialization are cleaned on each request without cache classes" do test "descendants loaded after framework initialization are cleaned on each request if reloading is enabled" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
config.reload_classes_only_on_change = false config.reload_classes_only_on_change = false
RUBY RUBY
@ -152,7 +152,7 @@ class Post < ApplicationRecord
test "reload constants on development" do test "reload constants on development" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/routes.rb", <<-RUBY app_file "config/routes.rb", <<-RUBY
@ -187,7 +187,7 @@ def self.counter; 2; end
test "does not reload constants on development if custom file watcher always returns false" do test "does not reload constants on development if custom file watcher always returns false" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
config.file_watcher = Class.new do config.file_watcher = Class.new do
def initialize(*); end def initialize(*); end
def updated?; false; end def updated?; false; end
@ -228,7 +228,7 @@ def self.counter; 2; end
test "added files (like db/schema.rb) also trigger reloading" do test "added files (like db/schema.rb) also trigger reloading" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/routes.rb", <<-RUBY app_file "config/routes.rb", <<-RUBY
@ -260,7 +260,7 @@ class User
test "dependencies reloading is followed by routes reloading" do test "dependencies reloading is followed by routes reloading" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/routes.rb", <<-RUBY app_file "config/routes.rb", <<-RUBY
@ -293,7 +293,7 @@ class User
test "routes are only loaded once on boot" do test "routes are only loaded once on boot" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/routes.rb", <<-RUBY app_file "config/routes.rb", <<-RUBY
@ -317,7 +317,7 @@ class User
test "columns migrations also trigger reloading" do test "columns migrations also trigger reloading" do
add_to_config <<-RUBY add_to_config <<-RUBY
config.cache_classes = false config.enable_reloading = true
RUBY RUBY
app_file "config/routes.rb", <<-RUBY app_file "config/routes.rb", <<-RUBY

@ -194,8 +194,8 @@ def app
assert_includes middleware, "ActionDispatch::Executor" assert_includes middleware, "ActionDispatch::Executor"
end end
test "does not include lock if cache_classes is set and so is eager_load" do test "does not include lock if reload is disabled and eager_load enabled" do
add_to_config "config.cache_classes = true" add_to_config "config.enable_reloading = false"
add_to_config "config.eager_load = true" add_to_config "config.eager_load = true"
boot! boot!
assert_not_includes middleware, "Rack::Lock" assert_not_includes middleware, "Rack::Lock"
@ -248,8 +248,8 @@ def app
assert_includes middleware, "ActionDispatch::DebugExceptions" assert_includes middleware, "ActionDispatch::DebugExceptions"
end end
test "removes ActionDispatch::Reloader if cache_classes is true" do test "removes ActionDispatch::Reloader if reload is disabled" do
add_to_config "config.cache_classes = true" add_to_config "config.enable_reloading = false"
boot! boot!
assert_not_includes middleware, "ActionDispatch::Reloader" assert_not_includes middleware, "ActionDispatch::Reloader"
end end

@ -138,15 +138,19 @@ class RESTfulController < ApplicationController
assert $zeitwerk_integration_test_post assert $zeitwerk_integration_test_post
end end
test "reloading is enabled if config.cache_classes is false" do test "reloading is enabled if config.enable_reloading is true" do
add_to_env_config "development", "config.enable_reloading = true"
boot boot
assert Rails.autoloaders.main.reloading_enabled? assert Rails.autoloaders.main.reloading_enabled?
assert_not Rails.autoloaders.once.reloading_enabled? assert_not Rails.autoloaders.once.reloading_enabled?
end end
test "reloading is disabled if config.cache_classes is true" do test "reloading is disabled if config.enable_reloading is false" do
boot("production") add_to_env_config "development", "config.enable_reloading = false"
boot
assert_not Rails.autoloaders.main.reloading_enabled? assert_not Rails.autoloaders.main.reloading_enabled?
assert_not Rails.autoloaders.once.reloading_enabled? assert_not Rails.autoloaders.once.reloading_enabled?