iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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 install
Try it Yourself »

Discussion

Loading…