Upgrading Solidus
With Solidus' maintenance policy, a release will receive security patches and other critical bug-fixes for 18 months after it's released to the public. This should give you plenty of time to upgrade to new versions of Solidus before your release reaches its EOL. You can find a list of the currently supported Solidus versions on the Security page of our website.
Because of the project's focus on stability and backwards compatibility, upgrading Solidus is usually a painless process: minor releases NEVER break public APIs, although they may deprecate APIs that will then be removed in the next major.
When upgrading, look at the changelog and make a note of any large refactoring or public API changes, then update your app accordingly. You should also make sure to update any extensions you have installed, since new releases may have come out to support the new Solidus version or take advantage of new functionality it introduces.
Solidus contains a task to help you with the upgrading process. Remember to run it when you get hands-on:
bin/rails g solidus:update
It will:
- Copy all new Solidus database migrations to your host application.
- Generate an initializer to help you update to the new defaults.
Ruby and Rails upgrades
Solidus' approach on Ruby and Ruby on Rails support is fairly simple: each minor release supports up to the oldest Ruby and Rails versions that are still maintained. For major releases, we could remove support for old but maintained versions if that brings some benefit, but still allowing you to update to a supported Ruby or Rails version before upgrading Solidus.
Solidus 2.10, for instance, introduced support for Rails 6.0, but it also works with Rails 5.2. As for Ruby, Solidus works with Ruby 2.4 and later, because 2.4 was the oldest maintained version at the time of release. However, you cannot use Rails 6 with Ruby 2.4, which means you will have to upgrade to at least Ruby 2.5 if you want to use Solidus with Rails 6. Another example, Solidus 4.0 removed support for Rails 6.0 & Rails 6.1, but, as Solidus 3.4 supports Rails 7, you can first update your store to Rails 7 and then go for Solidus 4.0.
When you upgrade Solidus, you should also make sure to upgrade your Ruby and Rails versions to the newest possible versions. Ruby upgrades are usually pretty smooth, while Rails provides amazing upgrade guides you can follow.
Upgrading dependencies
Solidus is just a Rails engine that runs as part of your application, so you should still take care to regularly upgrade any other dependencies in addition to Solidus. There are tools that can help you stay on top of version updates, such as Dependabot, but in general the best tool you can employ is a solid suite of automated unit and integration tests that verify the behavior of your application after an upgrade.
Dealing with deprecations
While it can be tempting to leave calls to deprecated APIs in place and wait for their removal before fixing them, this approach will come back to haunt you when you upgrade to a new major version and find that you need to update dozens of method calls that don't work anymore.
It's particularly important to understand how to handle deprecations correctly. The recommended approach is to fix deprecation warnings as soon as they arise. When you upgrade Solidus, run your entire test suite and copy all deprecation warnings to a separate file. In Bash, you can easily do it by running this command from your app's root:
$ bundle exec rspec 2>deprecations.txt
This will save all Solidus deprecations to the deprecations.txt
file. You will find that this file
contains a lot of duplicates, but you may remove them with another command:
$ cat deprecations.txt | sort | uniq
This will output a de-duplicated list of deprecations in your code. Once you have this, just go through the deprecations one by one and fix them. Then run your test suite again to ensure your app doesn't contain any deprecated code.
In some cases, deprecated code may come from Solidus extensions and not your own app, meaning you can't fix the deprecation yourself. When this happens, you can open an issue in the extension's repository to let the maintainer know that they need to update their extension.
Updating the database
Especially during major version upgrades, when you run the bin/rails g
solidus:update
task, new database migrations updating the Solidus database
schema might be copied to your host application.
It would be best if you never ran them blindly. Instead, look into them in detail, understand them, check if they could cause an issue with your production data, and, if needed, modify them to match your specific situation. Depending on your data volume, usage, and schema modifications on your side, you might prefer to ditch them or perform a longer but safer update journey. The documentation for the strong_migrations gem contains helpful tips you can check.
Updating preferences
There're some aspects of Solidus behavior that you can tweak on your application. For instance,
guest checkouts are allowed by default, but you can change it on the spree.rb
initializer:
Spree.config do |config|
config.allow_guest_checkout = false
end
Some defaults may change between Solidus versions. Those changes might break the expectations of
your application behavior. For that reason, Solidus comes with the Spree.load_defaults(version)
method to ensure that the implicit defaults (those you're not overriding on spree.rb
) stay the
same after an upgrade. This method is called on top of the spree.rb
file. E.g.:
Spree.load_defaults('3.0')
Spree.config do |config|
# ...
end
If you upgrade from Solidus 3.0 to Solidus 3.1, you won't have the
Spree.load_defaults
call in your initializer yet. Please, ensure that you add it before performing the upgrade!
After an upgrade, you should update the version passed to the Spree.load_defaults
method. However,
before that, you need to check which defaults have changed and decide what to do with them. You have
a couple of options:
- Adapt your application code to integrate the new default.
- Explicitly use the old default in
spree.rb
if you're sure you still want to use it. - Do nothing if the new default doesn't entail a change from your side.
Recall that Solidus comes with the solidus:update
generator to help you with
the process:
bin/rails g solidus:update
This command will generate a new initializer called new_solidus_defaults.rb
. All the defaults that
have changed in the latest version are displayed, each in a commented out line. That allows you to
act on each individual new preference performing one of the options given above. If you want to
integrate a new preference, you only need to uncomment its line. When you're done with all the
defaults, you can flip the version used in spree.rb
's Spree.load_defaults
call and remove
the new_solidus_defaults.rb
file altogether.
Internally, Spree.load_defaults
is a shortcut that forwards the same method to the configuration
object for every available Solidus component: core, backend & API. You'll see
that the #load_defaults
call, with the previous version as an argument, is
disassembled into the individual components in new_solidus_defaults.rb
. It
gives you more fine-grained control as you can flag as done an individual
component by updating its #load_defaults
version when you're done with it.
For instance, say that you're upgrading from Solidus 3.0 to 3.1, and three made-up defaults have changed:
- Core's
:core_pref_one
wasfalse
and now istrue
. - Core's
:core_pref_two
wasfalse
and now istrue
. - Backend's
:backend_pref
was'this'
and now is'that'
.
The generated new_solidus_defaults.rb
file would look something like the following:
Spree.config do |config|
config.load_defaults('3.0')
# config.core_pref_one = true
# config.core_pref_two = true
end
Spree::Backend::Config do |config|
config.load_defaults('3.0')
# config.backend_pref = 'that'
end
A sensible approach you could take to leave your application up to date could be:
- Adapt your app to take into account that
core_pref_one
istrue
and uncomment its line in the initializer. - Adapt your app to take into account that
core_pref_two
istrue
, remove lines forcore_pref_one
&core_pref_two
, and update theconfig.load_default
call within theSpree.config
block to take'3.1'
as parameter. - Adapt your app to take into account that
backend_pref
is'that'
. Remove thenew_solidus_defaults.rb
initializer and bump theSpree.load_defaults
call inspree.rb
to'3.1'
.