Read more

Best practice: How to manage versions in a Gemfile

Emanuel
July 26, 2023Software engineer at makandra GmbH

It most cases it's not necessary to add a version constraint next to your gems in the Gemfile. Since all versions are saved in the Gemfile.lock, everyone running bundle install will get exactly the same versions.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

There are some exceptions, where you can consider adding a version constrain to the Gemfile:

  • You are not checking in the Gemfile.lock into the version control (not recommended)
  • A specific gem has a bug in a more recent version (adding a comment for the reason is highly recommended)
  • You want to ensure no one upgrades a library with bundle update

An drawback of this approach is, that adding new gems might also upgrade existing gems. So check your Gemfile.lock carefully when submitting a commit. Note that the approach in this card works best, if you use bundle outdated together with bundle update some_gem --convervative for major updates, before running bundle update on all minor and patch updates.

Examples

Bad

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "2.7.6"

gem "rails", "~> 7.0.6"
gem "sqlite3", "~> 1.4"
gem "puma", "~> 5.0"
  • This blocks automatic updates of rails, sqlite3 and puma with bundle update

Note: bundle add will automatically add ~> with the current version of the new gem and you need to take care to remove this version constraint afterwards again.

Good

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "2.7.6"

gem "rails"
gem "sqlite3"
gem "puma"
  • All gems are easily updateable with bundle update

Good

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "2.7.6"

gem "rails", "~> 7.0.6" 
gem "sqlite3"
gem "puma"
  • bundle update will never perform a major rails update unless you change this line

Okay

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "2.7.6"

gem "rails"
gem "sqlite3", ">1.4.0" # CVE-XYZ
gem "puma"
  • Downgrades with bundler happens only in rare cases and will emit a warning Note: some_gem version regressed from a to b. Checking the Gemfile.lock carefully when submitting a commit should be good enough to prevent reintroducing previous issues.
  • If you have big concerns, that a downgrade might reintroduce a security issue again, you still might add this contraint
  • On the other hand, if you consequently enforce this, your rails line would have a long line of comments with CVEs

Good

source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "2.7.6"

gem "rails"
gem "sqlite3"
gem "puma", "<5.0" # Puma 5.0 does not work with our HMR middleware yet (see story #1234)
  • Preventing upgrades in case the newest version has a bug or is for some reason not working within the project
Emanuel
July 26, 2023Software engineer at makandra GmbH
Posted by Emanuel to makandra dev (2023-07-26 09:35)