aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2019-04-14 11:37:50 +0200
committerXavier Noria <fxn@hashref.com>2019-04-14 12:09:09 +0200
commit3e66ba91d511158e22f90ff96b594d61f40eda01 (patch)
tree97257467b80f6d7d087d198c5edac8f9651b3875
parentf8944ed22dc9453dea5814676fa49ce119a58726 (diff)
downloadrails-3e66ba91d511158e22f90ff96b594d61f40eda01.tar.gz
rails-3e66ba91d511158e22f90ff96b594d61f40eda01.tar.bz2
rails-3e66ba91d511158e22f90ff96b594d61f40eda01.zip
deprecates autoloading constants during initialization [closes #35745]
See rationale in the warning message included in the patch.
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/lib/rails/application/finisher.rb37
-rw-r--r--railties/test/application/configuration_test.rb55
3 files changed, 96 insertions, 0 deletions
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index ab400e5982..673cfde3d9 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Autoloading during initialization is deprecated.
+
+ *Xavier Noria*
+
* Only force `:async` ActiveJob adapter to `:inline` during seeding.
*BatedUrGonnaDie*
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index 1cf44a480c..109c560c80 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+require "active_support/core_ext/string/inflections"
+require "active_support/core_ext/array/conversions"
+
module Rails
class Application
module Finisher
@@ -21,6 +24,40 @@ module Rails
end
end
+ # This will become an error if/when we remove classic mode. The plan is
+ # autoloaders won't be configured up to this point in the finisher, so
+ # constants just won't be found, raising regular NameError exceptions.
+ initializer :warn_if_autoloaded, before: :let_zeitwerk_take_over do
+ next if config.cache_classes
+ next if ActiveSupport::Dependencies.autoloaded_constants.empty?
+
+ autoloaded = ActiveSupport::Dependencies.autoloaded_constants
+ constants = "constant".pluralize(autoloaded.size)
+ enum = autoloaded.to_sentence
+ have = autoloaded.size == 1 ? "has" : "have"
+ these = autoloaded.size == 1 ? "This" : "These"
+ example = autoloaded.first
+ example_klass = example.constantize.class
+
+ ActiveSupport::DescendantsTracker.clear
+ ActiveSupport::Dependencies.clear
+
+ ActiveSupport::Deprecation.warn(<<~WARNING)
+ Initialization autoloaded the #{constants} #{enum}.
+
+ Being able to do this is deprecated. Autoloading during initialization is going
+ to be an error condition in future versions of Rails.
+
+ Reloading does not reboot the application, and therefore code executed during
+ initialization does not run again. So, if you reload #{example}, for example,
+ the expected changes won't be reflected in that stale #{example_klass} object.
+
+ #{these} autoloaded #{constants} #{have} been unloaded.
+
+ Please, check the "Autoloading and Reloading Constants" guide for solutions.
+ WARNING
+ end
+
initializer :let_zeitwerk_take_over do
if config.autoloader == :zeitwerk
require "active_support/dependencies/zeitwerk_integration"
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index b8e167b488..a2e3e781c0 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -1704,6 +1704,61 @@ module ApplicationTests
end
end
+ test "autoloading during initialization gets deprecation message and clearing if config.cache_classes is false" do
+ app_file "lib/c.rb", <<~EOS
+ class C
+ extend ActiveSupport::DescendantsTracker
+ end
+
+ class X < C
+ end
+ EOS
+
+ app_file "app/models/d.rb", <<~EOS
+ require "c"
+
+ class D < C
+ end
+ EOS
+
+ app_file "config/initializers/autoload.rb", "D"
+
+ app "development"
+
+ # TODO: Test deprecation message, assert_depcrecated { app "development" }
+ # does not collect it.
+
+ assert_equal [X], C.descendants
+ assert_empty ActiveSupport::Dependencies.autoloaded_constants
+ end
+
+ test "autoloading during initialization triggers nothing if config.cache_classes is true" do
+ app_file "lib/c.rb", <<~EOS
+ class C
+ extend ActiveSupport::DescendantsTracker
+ end
+
+ class X < C
+ end
+ EOS
+
+ app_file "app/models/d.rb", <<~EOS
+ require "c"
+
+ class D < C
+ end
+ EOS
+
+ app_file "config/initializers/autoload.rb", "D"
+
+ app "production"
+
+ # TODO: Test no deprecation message is issued.
+
+ assert_equal [X, D], C.descendants
+ end
+
+
test "raises with proper error message if no database configuration found" do
FileUtils.rm("#{app_path}/config/database.yml")
err = assert_raises RuntimeError do