Skip to content

Commit

Permalink
Merge pull request #652 from rails/rm-mechanism
Browse files Browse the repository at this point in the history
Require applications to have reloading enabled in the managed environ…
  • Loading branch information
fxn authored Sep 8, 2021
2 parents 53d9e17 + 24cc80e commit eff7850
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 25 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Next Release

* Require applications to have reloading enabled in the managed environments.

## 2.1.1

* Avoid -I rubylibdir with default-gem bundler
Expand Down
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ automatically add `./bin` to your `PATH` when you `cd` into your application.
Simply create an `.envrc` file with the command `PATH_add bin` in your
Rails directory.

### Enable reloading

Spring reloads application code, and therefore needs the application to have
reloading enabled.

Please, make sure `config.cache_classes` is `false` in the environments that
Spring manages. That setting is typically configured in
`config/environments/*.rb`. In particular, make sure it is `false` for the
`test` environment.

### Usage

For this walkthrough I've generated a new Rails application, and run
Expand Down Expand Up @@ -257,12 +267,10 @@ run through Spring, set the `DISABLE_SPRING` environment variable.

## Class reloading

Spring uses Rails' class reloading mechanism
(`ActiveSupport::Dependencies`) to keep your code up to date between
test runs. This is the same mechanism which allows you to see changes
during development when you refresh the page. However, you may never
have used this mechanism with your `test` environment before, and this
can cause problems.
Spring uses Rails' class reloading mechanism to keep your code up to date
between test runs. This is the same mechanism which allows you to see changes
during development when you refresh the page. However, you may never have used
this mechanism with your `test` environment before, and this can cause problems.

It's important to realise that code reloading means that the constants
in your application are *different objects* after files have changed:
Expand Down
25 changes: 6 additions & 19 deletions lib/spring/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,22 +95,17 @@ def preload
raise "Spring only supports Rails >= 5.2.0"
end

# config/environments/test.rb will have config.cache_classes = true. However
# we want it to be false so that we can reload files. This is a hack to
# override the effect of config.cache_classes = true. We can then actually
# set config.cache_classes = false after loading the environment.
Rails::Application.initializer :initialize_dependency_mechanism, group: :all do
# Rails 7 dropped classic mode, and this setter does not exist anymore.
if ActiveSupport::Dependencies.respond_to?(:mechanism=)
ActiveSupport::Dependencies.mechanism = :load
Rails::Application.initializer :ensure_reloading_is_enabled, group: :all do
if Rails.application.config.cache_classes
raise <<-MSG.strip_heredoc
Spring reloads, and therefore needs the application to have reloading enabled.
Please, set config.cache_classes to false in config/environments/#{Rails.env}.rb.
MSG
end
end

require Spring.application_root_path.join("config", "environment")

@original_cache_classes = Rails.application.config.cache_classes
Rails.application.config.cache_classes = false

disconnect_database

@preloaded = :success
Expand Down Expand Up @@ -195,14 +190,6 @@ def serve(client)
# Load in the current env vars, except those which *were* changed when Spring started
env.each { |k, v| ENV[k] ||= v }

# requiring is faster, so if config.cache_classes was true in
# the environment's config file, then we can respect that from
# here on as we no longer need constant reloading.
if @original_cache_classes
ActiveSupport::Dependencies.mechanism = :require
Rails.application.config.cache_classes = true
end

connect_database
srand

Expand Down
9 changes: 9 additions & 0 deletions test/support/acceptance_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ def without_gem(name)
refute_output_includes "bin/rails runner ''", stderr: 'Running via Spring preloader in process'
end

test "raises if config.cache_classes is true" do
config_path = app.path("config/environments/development.rb")
config = File.read(config_path)
config.sub!(/config.cache_classes\s*=\s*false/, "config.cache_classes = true")
File.write(config_path, config)

assert_failure "bin/rails runner 1", stderr: "Please, set config.cache_classes to false"
end

test "test changes are picked up" do
assert_speedup do
assert_success app.spring_test_command, stdout: "0 failures"
Expand Down

0 comments on commit eff7850

Please sign in to comment.