Skip to main content
Version: 4.0

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:

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

caution

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.

info

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 was false and now is true.
  • Core's :core_pref_two was false and now is true.
  • 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 is true and uncomment its line in the initializer.
  • Adapt your app to take into account that core_pref_two is true, remove lines for core_pref_one & core_pref_two, and update the config.load_default call within the Spree.config block to take '3.1' as parameter.
  • Adapt your app to take into account that backend_pref is 'that'. Remove the new_solidus_defaults.rb initializer and bump the Spree.load_defaults call in spree.rb to '3.1'.