Gems / Bundler
RubyGems is Ruby’s package manager. gem installs/lists/removes packages; bundler + Gemfile declares per-project dependencies with lockfiles. Together they handle install, version pinning, security audits, and packaging your own gems.
gem, Bundler, Gemfile, publish
EXAMPLE
# 1) System-wide gem CLI
gem install rails # latest version
gem install rails -v 7.1.3 # specific version
gem install rails -v '~> 7.1' # latest 7.1.x
gem uninstall rails
gem list # installed gems
gem list rails # filter
gem outdated # what's newer
gem update rails
gem update --system # update RubyGems itself
gem info rails # show metadata
gem env # show paths, version
gem cleanup # remove old versions
# 2) Bundler — per-project dependency management
# Install bundler:
gem install bundler
# Create a Gemfile in your project root
source 'https://rubygems.org'
ruby '3.3.0' # required Ruby version (or .ruby-version file)
gem 'rails', '~> 7.1.0'
gem 'pg', '~> 1.5'
gem 'puma', '~> 6.0'
gem 'dotenv-rails', groups: [:development, :test]
group :development, :test do
gem 'rspec-rails'
gem 'factory_bot_rails'
gem 'pry-byebug'
end
group :development do
gem 'rubocop', require: false
gem 'brakeman', require: false
gem 'bundler-audit', require: false
end
group :production do
gem 'sentry-ruby'
gem 'sentry-rails'
end
# 3) Install + lock
bundle install # installs + writes Gemfile.lock
bundle install --without production # skip groups (deprecated; use bundle config)
bundle config set without 'production'
bundle update rails # update one gem
bundle update # update all
bundle outdated # list outdated
bundle clean # remove unused
# Gemfile.lock — COMMIT THIS. Pins exact versions for reproducibility.
# 4) Run scripts within bundle context
bundle exec rake db:migrate
bundle exec rails s
bundle exec rspec
# Without 'bundle exec' you might pick up wrong gem version.
# Tip: alias 'be=bundle exec' or use 'binstubs':
bundle binstubs rails --path bin
./bin/rails s
# 5) Common version specifiers
gem 'rails', '7.1.3' # exact
gem 'rails', '>= 7.1.0' # at least
gem 'rails', '~> 7.1.0' # >= 7.1.0, < 7.2 (pessimistic)
gem 'rails', '~> 7.1' # >= 7.1, < 8.0
gem 'rails', '>= 7.1', '< 7.5' # range
gem 'rails' # any (DANGEROUS in prod)
# Use '~>' generously. It allows patches + minor updates without breaking changes.
# 6) Source alternatives
gem 'private-gem', source: 'https://gems.mycompany.com'
gem 'github-gem', github: 'user/repo', branch: 'main'
gem 'local-gem', path: '../local-gem'
gem 'tagged-gem', github: 'user/repo', tag: 'v1.2.3'
# 7) Bundler config
bundle config set frozen true # CI: refuse to update Gemfile.lock
bundle config set deployment true # production: only install Gemfile.lock
bundle config set path 'vendor/bundle' # local install path (containerised builds)
bundle config set jobs 4 # parallel install
bundle config list # show all
# 8) Security — audit dependencies
gem install bundler-audit
bundle-audit check --update
# Or use 'bundle audit' (gem version) — same checks against ruby-advisory-db.
# Failing CVE → fix gem version → re-audit.
# 9) Performance — multi-stage gem install
# In Docker:
# Copy Gemfile + Gemfile.lock first; bundle install; then copy code.
COPY Gemfile Gemfile.lock ./
RUN bundle config set deployment true && bundle install
COPY . .
# Bundle is cached across builds until Gemfile changes.
# 10) Publishing your own gem
# Create gemspec
# my_gem.gemspec
Gem::Specification.new do |spec|
spec.name = 'my_gem'
spec.version = '0.1.0'
spec.summary = 'Short summary'
spec.description = 'Longer description'
spec.authors = ['Mara']
spec.email = ['mara@example.com']
spec.files = Dir['lib/**/*', 'README.md', 'LICENSE']
spec.required_ruby_version = '>= 3.0'
spec.add_dependency 'rest-client', '~> 2.1'
spec.add_development_dependency 'rspec', '~> 3.12'
spec.metadata['source_code_uri'] = 'https://github.com/me/my_gem'
end
# Build + push
gem build my_gem.gemspec # creates my_gem-0.1.0.gem
gem push my_gem-0.1.0.gem # publish to rubygems.org
# Yank a bad release
gem yank my_gem -v 0.1.0
# 11) Private gem servers
# • geminabox — self-hosted
# • Gemfury — managed
# • GitHub Packages — GitHub-hosted with Bundler config
# • Private rubygems.org organisations
# 12) Common gems by use case
# • Web: rails, sinatra, hanami
# • DB: pg, mysql2, redis, sequel
# • Auth: devise, sorcery, omniauth, authentigem
# • Testing: rspec, minitest, factory_bot, capybara, vcr
# • Background: sidekiq, resque, good_job
# • Linting: rubocop, brakeman
# • API: grape, rack, faraday
# • CSV/JSON: csv (stdlib), oj (fast JSON)
# • Templating: erb (stdlib), haml, slim
# 13) Multi-version Ruby — rbenv / asdf
# .ruby-version
3.3.0
# rbenv install 3.3.0
# rbenv local 3.3.0
# Bundler respects .ruby-version automatically.
# 14) Common bugs
# • Gemfile + Gemfile.lock drift in CI → 'bundle install --frozen' fails; commit lockfile
# • 'gem install' system-wide; rbenv/asdf per-user — they shadow each other; understand which Ruby you're using
# • Production install without --deployment / frozen → unexpected updates
# • bundle update without args → updates EVERYTHING; review diff
# • Forgetting bundle exec → loads global gem version, not Gemfile-pinned
# • require: false for gems used only at CLI time (rubocop, brakeman) — required
# • Native extensions (nokogiri, pg) fail compilation on Alpine — install build tools
# • Adding gem to wrong group → missing in production
# • Gemfile.lock conflicts during merges → run 'bundle install' to regenerate
# • Hardcoded path to bundler instead of binstubs → fragile
Why it matters
Use Bundler with a committed Gemfile.lock for reproducible installs, group dev/test/prod dependencies separately, run everything with bundle exec (or binstubs), and audit with bundler-audit in CI. Pessimistic version constraints (~>) get you safe patches; for new gems, scaffold a .gemspec and publish to RubyGems or a private server.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Gemfile source 'https://rubygems.org' gem 'sinatra' # Install bundle installTry it Yourself »
Discussion
Loading…