aboutsummaryrefslogtreecommitdiffstats
path: root/guides/source/upgrading_ruby_on_rails.md
diff options
context:
space:
mode:
Diffstat (limited to 'guides/source/upgrading_ruby_on_rails.md')
-rw-r--r--guides/source/upgrading_ruby_on_rails.md96
1 files changed, 70 insertions, 26 deletions
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 54f014293d..05980d1614 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -184,41 +184,21 @@ That may be handy if you need to preload STIs or configure a custom inflector, f
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:
+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"`.
-```ruby
-# config/application.rb
+Compatibility can be checked with the `zeitwerk:check` task:
-config.load_defaults "6.0"
-config.autoloader = :classic
```
-
-and then running
-
+$ bin/rails zeitwerk:check
+Hold on, I am eager loading the application.
+All is good!
```
-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 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)
-```
+If your application has STIs, please check their section in the guide [Autoloading and Reloading Constants (Zeitwerk Mode)](autoloading_and_reloading_constants.html#single-table-inheritance).
#### Qualified names in class and module definitions
@@ -270,6 +250,16 @@ In that case, `app/models/concerns` is assumed to be a root directory (because i
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.
+#### Having `app` in the autoload paths
+
+Some projects want something like `app/api/base.rb` to define `API::Base`, and add `app` to the autoload paths to accomplish that in `classic` mode. Since Rails adds all subdirectories of `app` to the autoload paths automatically, we have another situation in which there are nested root directories, so that setup no longer works. Similar principle we explained above with `concerns`.
+
+If you want to keep that structure, you'll need to delete the subdirectory from the autoload paths in an initializer:
+
+```ruby
+ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/api")
+```
+
#### Autoloaded Constants and Explicit Namespaces
If a namespace is defined in a file, as `Hotel` is here:
@@ -391,6 +381,12 @@ To fix this, just remove the wildcards:
config.autoload_paths << "#{config.root}/lib"
```
+#### Eager loading and autoloading are consistent
+
+In `classic` mode, if `app/models/foo.rb` defines `Bar`, you won't be able to autoload that file, but eager loading will work because it loads files recursively blindly. This can be a source of errors if you test things first eager loading, execution may fail later autoloading.
+
+In `zeitwerk` mode both loading modes are consistent, they fail and err in the same files.
+
#### How to Use the Classic Autoloader in Rails 6
Applications can load Rails 6 defaults and still use the classic autoloader by setting `config.autoloader` this way:
@@ -402,6 +398,54 @@ config.load_defaults "6.0"
config.autoloader = :classic
```
+### Active Storage assignment behavior change
+
+In Rails 5.2, assigning to a collection of attachments declared with `has_many_attached` appended new files:
+
+```ruby
+class User < ApplicationRecord
+ has_many_attached :highlights
+end
+
+user.highlights.attach(filename: "funky.jpg", ...)
+user.higlights.count # => 1
+
+blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...)
+user.update!(highlights: [ blob ])
+
+user.highlights.count # => 2
+user.highlights.first.filename # => "funky.jpg"
+user.highlights.second.filename # => "town.jpg"
+```
+
+With the default configuration for Rails 6.0, assigning to a collection of attachments replaces existing files
+instead of appending to them. This matches Active Record behavior when assigning to a collection association:
+
+```ruby
+user.highlights.attach(filename: "funky.jpg", ...)
+user.highlights.count # => 1
+
+blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...)
+user.update!(highlights: [ blob ])
+
+user.highlights.count # => 1
+user.highlights.first.filename # => "town.jpg"
+```
+
+`#attach` can be used to add new attachments without removing the existing ones:
+
+```ruby
+blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg", ...)
+user.highlights.attach(blob)
+
+user.highlights.count # => 2
+user.highlights.first.filename # => "funky.jpg"
+user.highlights.second.filename # => "town.jpg"
+```
+
+Opt in to the new default behavior by setting `config.active_storage.replace_on_assign_to_many` to `true`.
+The old behavior will be deprecated in Rails 6.1 and removed in a subsequent release.
+
Upgrading from Rails 5.1 to Rails 5.2
-------------------------------------