Last Updated on September 9, 2023 by Christopher G Mendla
Using outdated gems in your Ruby on Rails application introduces vulnerabilities to your Rails Applications. There is an easy way to find outdated gems using the Bundle Outdated command.
Updating your Rails Applications
Do not go blindly along the updating path. Use version control and test the results of your updates. Be sure you have a solid backup and recovery plan in place.
Check your Rails version
The first thing to do is to check to see if you are on a current version of Ruby and Rails. The commands are ‘rails -v’ and ‘ruby -v’. Compare that with the latest releases of Ruby and Rails. Note that upgrades can be tricky so proceed with caution.
- https://www.ruby-lang.org/en/downloads/releases/ A list of all Ruby releases .
- https://rubygems.org/gems/rails/versions A list of all Rails releases.
If you are significantly behind in your Ruby or Rails releases, you need to determine if you should update them first or update the outdated gems first. When updating Rails, you should update ALL of the code that changed between releases by checking railsdiff.org. Too many developers and teams just make the changes they think are critical which results in the underlying application code diverging from the true release code.
Check for outdated gems
The next step is to determine how many outdated gems you have. The basic command is ‘bundle outdated’. However, you can modify that with grep and a pipe to get a count:
$ bundle outdated | grep -c "*"
This will return the number of outdated gems. This pipes the bundle outdated command to grep. The -c says count and the “*” is a handy way to get a unique count due to the way the list is returned.
Not all gems can be updated due to dependencies.
If you are using a test suite and rubocop, now would be a good time to run the test suite. The next step is to run ‘bundle outdated’ to see the gems. You will get results similar to the following
$ bundle outdated
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies............
Outdated gems included in the bundle:
* actioncable (newest 5.2.3, installed 5.0.2)
* actionmailer (newest 5.2.3, installed 5.0.2)
* actionpack (newest 5.2.3, installed 5.0.2)
* actionview (newest 5.2.3, installed 5.0.2)
* active_model_serializers (newest 0.10.9, installed 0.10.4) in groups "default"
* activejob (newest 5.2.3, installed 5.0.2)
* activemodel (newest 5.2.3, installed 5.0.2)
* activerecord (newest 5.2.3, installed 5.0.2)
* activesupport (newest 5.2.3, installed 5.0.2)
* arel (newest 9.0.0, installed 7.1.4)
* autoprefixer-rails (newest 9.5.1, installed 7.1.2.3) in groups "default"
* bcrypt (newest 3.1.12, installed 3.1.11, requested ~> 3.1.7) in groups "default"
. . .
Note that some of the gems show as being in a group and others do not. The gems that are shown as being in a group are gems that are listed in your gemfile explicitly. It is a good practice to call out the version in your gemfile
For example, here are three basic ways of calling a gem
gem samplegem # no version is specified
gem samplegem, '1.1.1' # locks that gem to version 1.1.1
gem samplegem, '~> 1.1.1' # calls for version 1.1.1 but bundle update
# will update to the highest minor version
Run bundle update
You can try ‘bundle update’. This will attempt to update all the gems that are not explicitly called in the gemfile or can be updated to a version compatible with the ‘~>’ version specified.
Run your tests
Now, run your tests. Are they still passing? Test the app in development. Is it still running OK? If you are lucky, it will test and run OK. If not, you will need to do some research as to why it failed. You are working with version control and can reset the branch, right?
Alternative – Update each gem manually
Another alternative is to manually update each gem and then run your test suite. That can be time consuming and doesn’t always give predictable results. For example.
$ gem update samplegem
$ bundle install
$ rspec # or whatever command launches your test suite.
You will probably not be able to get all of the gems updated. If you want to see what other gems use a particular gem, you can do this
$ gem dependency -R thor
Gem thor-0.20.3
bundler (~> 1.0, development)
Used by
rack-test-1.1.0 (thor (~> 0.19, development))
railties-5.2.2.1 (thor (>= 0.19.0, < 2.0))
This shows which gems use the thor gem.
Once you get the gems that are not in the gemfile, you will need to look at the gems that are called out in your gemfile.
For example, if we see a line in the ‘bundle outdated’ results such as
* puma (newest 3.12.1, installed 3.8.1, requested ~> 3.0) in groups "development, test"
We should be able to find that line in the ‘development, test’ group in our gemfile.
group :development, :test do
gem 'byebug', platform: :mri
gem 'pry-rails'
# Use Puma as the dev app server
gem 'puma', '~> 3.0'
end
To update to the latest current version of Puma (assuming there are no compatibility issues, you can change it as follows
group :development, :test do
gem 'byebug', platform: :mri
gem 'pry-rails'
# Use Puma as the dev app server
gem 'puma', '~> 3.12.1'
end
Bundle install and test
Then run ‘bundle install’ . Then run your test suite.
Summary
The process is tedious. In a production environment, you will probably be running bundle outdated several times a week. Constant integration apps such as Jenkins can be configured to fail builds that have over a set number of outdated gems.
You will occasionally run into situations where updating a gem causes conflicts that will break your app, build or tests.