Content
View differences
Updated by Christophe Bliard over 3 years ago
Since Rails 5.0, Rails provides the ability to [configure which default values are applied](https://guides.rubyonrails.org/configuring.html#versioned-default-values) to the application, to ease upgrades.
In `config/application`, it should look like:
```ruby
module OpenProject
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
...
end
end
```
This ensure that the defaults for a specific version are applied.
As this line is absent for OpenProject, the defaults applied currently are mostly from Rails 4.2. Mostly, because some settings are explicitly set in configuration files.
For instance, the digest algorithm used to generate non-sensitive digests has changed from MD5 to SHA-1 in Rails 5.2. To use it, a [commit](https://github.com/opf/openproject/commit/e6d578ad98ea262c8743649ca035f2a32fedc09f) used `config.active_support.use_sha1_digests = true`, and [another one](https://github.com/opf/openproject/commit/bc0839d104926a5c76242276cd5d000e1639bb49) changed it to `config.active_support.hash_digest_class = ::Digest::SHA1`. This setting is lagging behind. The new default for Rails 7.0 is `OpenSSL::Digest::SHA256`.
There are a [lot of new defaults](https://guides.rubyonrails.org/configuring.html#default-values-for-target-version-7-0) in last versions of Rails, and very few of them are actually applied in our codebase.
Another example: we are seeing the following message when starting the application:
```text
DEPRECATION WARNING: Using legacy connection handling is deprecated. Please set
`legacy_connection_handling` to `false` in your application.
The new connection handling does not support `connection_handlers`
getter and setter.
Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling
```
The line [`config.active_record.legacy_connection_handling = false`](https://guides.rubyonrails.org/configuring.html#config-active-record-legacy-connection-handling) can be added to our configuration as advised. But in fact, [this is already the default since Rails 6.1](https://guides.rubyonrails.org/configuring.html#config-active-record-legacy-connection-handling). If we had `config.load_defaults 6.1` (or `7.0`), we would never have seen this deprecation warning.
## Goal
Have `config.load_defaults 7.0` in `config/application.rb`.
But it cannot be done in one single step, because some of Rails 7.0 defaults may break our application. We need to take the upgrade route
### Proposed action plan
Do the [upgrade as recommended by Rails](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#configure-framework-defaults):
* Start with a commented `# config.load_defaults 5.0` in `config/application.rb`
* Have all new-framework-default initializers for all Rails version from 5.0 to 7.0 ready:
* `config/initializers/new_framework_defaults_5_0.rb` ([link](https://github.com/rails/rails/blob/5-0-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt))
* `config/initializers/new_framework_defaults_5_1.rb` ([link](https://github.com/rails/rails/blob/5-1-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_1.rb.tt))
* `config/initializers/new_framework_defaults_5_2.rb` ([link](https://github.com/rails/rails/blob/5-2-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt))
* `config/initializers/new_framework_defaults_6_0.rb` ([link](https://github.com/rails/rails/blob/6-0-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt))
* `config/initializers/new_framework_defaults_6_1.rb` ([link](https://github.com/rails/rails/blob/6-1-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_1.rb.tt))
* `config/initializers/new_framework_defaults_7_0.rb` ([link](https://github.com/rails/rails/blob/7-0-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt))
* The `new_framework_defaults_x_y.rb` files work like this:
* when evaluated, they do not modify any defaults. In fact they contain only commented code (the ones for version 5.0 and 5.1 will have to be adapted to follow the same pattern).
* Rails is using default from version `n`. To use introduce defaults from version `n+1`, settings from file `new_framework_defaults_{n+1}.rb` should be uncommented to be applied. Once all are applied, the version given to `load_defaults` can be incremented to [apply the defaults](https://github.com/rails/rails/blob/9a5c17b1f008d5a62381d0eb563abf73630e9158/railties/lib/rails/application/configuration.rb#L89-L325) specific to the given version `config.load_defaults {n+1}`. The file `new_framework_defaults_{n+1}.rb` is no longer necessary and should be deleted.
* Uncomment settings in `config/initializers/new_framework_defaults_5_0.rb` one by one, using the recommendations from the [Upgrade guide](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html), and modifying application code as necessary. Try to deploy each setting atomically and watch AppSignal for any suspect behavior,
* Once all settings in `new_framework_defaults_5_0.rb` are uncommented, that means the app is now running on Rails 5.0 defaults.
* `# config.load_defaults 5.0` can be uncommented to `config.load_defaults 5.0`. It will [apply the defaults](https://github.com/rails/rails/blob/9a5c17b1f008d5a62381d0eb563abf73630e9158/railties/lib/rails/application/configuration.rb#L89-L325) specific to the version 5.0, which are the same as the ones in `new_framework_defaults_5_0.rb`.
* File `new_framework_defaults_{n+1}.rb` can be deleted
* Use `config.load_defaults 5.0`
* Delete `config/initializers/new_framework_defaults_5_0.rb`
* Then we do it again for each Rails version:
* Uncomment settings in `config/initializers/new_framework_defaults_5_1.rb` atomically until all the file is uncommented
* Use `config.load_defaults 5.1`
* Delete `config/initializers/new_framework_defaults_5_1.rb`
* Uncomment settings in `config/initializers/new_framework_defaults_5_2.rb` atomically until all the file is uncommented
* Use `config.load_defaults 5.2`
* Delete `config/initializers/new_framework_defaults_5_2.rb`
* And so on...
Any setting diverging from Rails defaults for a long period of time should be put in `config/initializers/overridden_rails_default_of_x_y.rb`. This will allow us to still delete the `new_framework_default_x_y.rb` files and increase the `config.load_default` parameter while making the changes clearer about how we diverge from these defaults.
To ensure we do not break things by moving too fast, maybe we should limit the number of Rails defaults upgrades we do within each OpenProject Release. That means never upgrade Rails defaults for a patch release.
* OpenProject 12.5.0
* migrate to Rails 5.0 defaults
* OpenProject 12.5.1
* nothing
* OpenProject 12.5.2
* nothing
* OpenProject 13.0
* migrate to Rails 5.1 defaults
* OpenProject 13.1
* migrate to Rails 5.2 defaults
* OpenProject 13.2
* migrate to Rails 6.0 defaults
We should be free to uncomment some defaults from any `config/initializers/new_framework_defaults_xxx.rb` file where we see fit while still being cautious about side-effects.
In `config/application`, it should look like:
```ruby
module OpenProject
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
...
end
end
```
This ensure that the defaults for a specific version are applied.
As this line is absent for OpenProject, the defaults applied currently are mostly from Rails 4.2. Mostly, because some settings are explicitly set in configuration files.
For instance, the digest algorithm used to generate non-sensitive digests has changed from MD5 to SHA-1 in Rails 5.2. To use it, a [commit](https://github.com/opf/openproject/commit/e6d578ad98ea262c8743649ca035f2a32fedc09f) used `config.active_support.use_sha1_digests = true`, and [another one](https://github.com/opf/openproject/commit/bc0839d104926a5c76242276cd5d000e1639bb49) changed it to `config.active_support.hash_digest_class = ::Digest::SHA1`. This setting is lagging behind. The new default for Rails 7.0 is `OpenSSL::Digest::SHA256`.
There are a [lot of new defaults](https://guides.rubyonrails.org/configuring.html#default-values-for-target-version-7-0) in last versions of Rails, and very few of them are actually applied in our codebase.
Another example: we are seeing the following message when starting the application:
```text
DEPRECATION WARNING: Using legacy connection handling is deprecated. Please set
`legacy_connection_handling` to `false` in your application.
The new connection handling does not support `connection_handlers`
getter and setter.
Read more about how to migrate at: https://guides.rubyonrails.org/active_record_multiple_databases.html#migrate-to-the-new-connection-handling
```
The line [`config.active_record.legacy_connection_handling = false`](https://guides.rubyonrails.org/configuring.html#config-active-record-legacy-connection-handling) can be added to our configuration as advised. But in fact, [this is already the default since Rails 6.1](https://guides.rubyonrails.org/configuring.html#config-active-record-legacy-connection-handling). If we had `config.load_defaults 6.1` (or `7.0`), we would never have seen this deprecation warning.
## Goal
Have `config.load_defaults 7.0` in `config/application.rb`.
But it cannot be done in one single step, because some of Rails 7.0 defaults may break our application. We need to take the upgrade route
### Proposed action plan
Do the [upgrade as recommended by Rails](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#configure-framework-defaults):
* Start with a commented `# config.load_defaults 5.0` in `config/application.rb`
* Have all new-framework-default initializers for all Rails version from 5.0 to 7.0 ready:
* `config/initializers/new_framework_defaults_5_0.rb` ([link](https://github.com/rails/rails/blob/5-0-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt))
* `config/initializers/new_framework_defaults_5_1.rb` ([link](https://github.com/rails/rails/blob/5-1-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_1.rb.tt))
* `config/initializers/new_framework_defaults_5_2.rb` ([link](https://github.com/rails/rails/blob/5-2-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_5_2.rb.tt))
* `config/initializers/new_framework_defaults_6_0.rb` ([link](https://github.com/rails/rails/blob/6-0-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt))
* `config/initializers/new_framework_defaults_6_1.rb` ([link](https://github.com/rails/rails/blob/6-1-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_1.rb.tt))
* `config/initializers/new_framework_defaults_7_0.rb` ([link](https://github.com/rails/rails/blob/7-0-stable/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_0.rb.tt))
* The `new_framework_defaults_x_y.rb` files work like this:
* when evaluated, they do not modify any defaults. In fact they contain only commented code (the ones for version 5.0 and 5.1 will have to be adapted to follow the same pattern).
* Rails is using default from version `n`. To use introduce defaults from version `n+1`, settings from file `new_framework_defaults_{n+1}.rb` should be uncommented to be applied. Once all are applied, the version given to `load_defaults` can be incremented to [apply the defaults](https://github.com/rails/rails/blob/9a5c17b1f008d5a62381d0eb563abf73630e9158/railties/lib/rails/application/configuration.rb#L89-L325) specific to the given version `config.load_defaults {n+1}`. The file `new_framework_defaults_{n+1}.rb` is no longer necessary and should be deleted.
* Uncomment settings in `config/initializers/new_framework_defaults_5_0.rb` one by one, using the recommendations from the [Upgrade guide](https://guides.rubyonrails.org/upgrading_ruby_on_rails.html), and modifying application code as necessary. Try to deploy each setting atomically and watch AppSignal for any suspect behavior,
* Once all settings in `new_framework_defaults_5_0.rb` are uncommented, that means the app is now running on Rails 5.0 defaults.
* `# config.load_defaults 5.0` can be uncommented to `config.load_defaults 5.0`. It will [apply the defaults](https://github.com/rails/rails/blob/9a5c17b1f008d5a62381d0eb563abf73630e9158/railties/lib/rails/application/configuration.rb#L89-L325) specific to the version 5.0, which are the same as the ones in `new_framework_defaults_5_0.rb`.
* File `new_framework_defaults_{n+1}.rb` can be deleted
* Use `config.load_defaults 5.0`
* Delete `config/initializers/new_framework_defaults_5_0.rb`
* Then we do it again for each Rails version:
* Uncomment settings in `config/initializers/new_framework_defaults_5_1.rb` atomically until all the file is uncommented
* Use `config.load_defaults 5.1`
* Delete `config/initializers/new_framework_defaults_5_1.rb`
* Uncomment settings in `config/initializers/new_framework_defaults_5_2.rb` atomically until all the file is uncommented
* Use `config.load_defaults 5.2`
* Delete `config/initializers/new_framework_defaults_5_2.rb`
* And so on...
Any setting diverging from Rails defaults for a long period of time should be put in `config/initializers/overridden_rails_default_of_x_y.rb`. This will allow us to still delete the `new_framework_default_x_y.rb` files and increase the `config.load_default` parameter while making the changes clearer about how we diverge from these defaults.
To ensure we do not break things by moving too fast, maybe we should limit the number of Rails defaults upgrades we do within each OpenProject Release. That means never upgrade Rails defaults for a patch release.
* OpenProject 12.5.0
* migrate to Rails 5.0 defaults
* OpenProject 12.5.1
* nothing
* OpenProject 12.5.2
* nothing
* OpenProject 13.0
* migrate to Rails 5.1 defaults
* OpenProject 13.1
* migrate to Rails 5.2 defaults
* OpenProject 13.2
* migrate to Rails 6.0 defaults
We should be free to uncomment some defaults from any `config/initializers/new_framework_defaults_xxx.rb` file where we see fit while still being cautious about side-effects.