Ruby in 2024
2024-12-23
It's funny how things come full circle. The last time I wrote Ruby code was back in 2014, while still at the university. Now, after spending almost 10 years working with other languages and technologies, I find myself drawn back to it for a side project I've been working on in my spare time. There's something comforting about returning to an old language you liked - it's like catching up with an old friend you haven't seen in years.
Before diving back into my project, I needed to figure out how to set up a proper Ruby development environment again. What surprised (and honestly, delighted) me was discovering that the setup process hasn't changed much since 2014. In a world where development tools and best practices seem to change every few months, this stability is refreshing.
Ruby Version Managers
The first thing you need when setting up a programming language on your machine is a version manager for that language (though newer languages tend to include this as part of their core tooling). Once you start juggling multiple projects, you'll likely need to run different versions of the language depending on the project, and you want to be able to switch between them seamlessly.
The Ruby ecosystem offers several version managers. While rvm
is the oldest and still maintained, the community has largely moved on to newer alternatives:
All these tools focus solely on switching between Ruby versions - they don't handle the actual compilation and installation of Ruby itself. For that part, they all depend on ruby-build, a tool developed by the rbenv team that handles the heavy lifting of compiling and installing Ruby from source.
After trying out the different options, I settled on rbenv
for a few reasons:
- It does one thing (managing Ruby versions) and does it well. While the alternatives support multiple languages through community-managed plug-ins (with different quality levels),
rbenv
focuses only on Ruby which is the only thing I needed. - It's simple enough that I can understand what's happening under the hood
- It's been around long enough to be boring - and in development tools, boring is often good
Setting Up rbenv
Getting started with rbenv is straightforward. Depending on your system, install it with:
- Archlinux:
sudo pacman -S rbenv
- Homebrew:
brew install rbenv
Then initialize it by running rbenv init
once. This will add the following line at the end of your .profile
or .bash_profile
file:
eval "$(rbenv init - --no-rehash bash)"
Here's a gotcha I ran into: the line needs to appear before your .bashrc
loading or bash autocompletion won't work (at least in my case):
eval "$(rbenv init - --no-rehash bash)"
[[ -f ~/.bashrc ]] && . ~/.bashrc
Once everything's set up, source your .bash_profile
with . .bash_profile
or simply log out and then log in to activate rbenv
. Then run which ruby
to check that it points to rbenv's path now:
$ which ruby
$HOME/.rbenv/shims/ruby
Managing Ruby Versions
Now that you have rbenv
installed and initialized, you can use it to manage your ruby versions.
Here are some useful commands to manage ruby versions:
- List the latest stable versions:
rbenv install --list
- Install a Ruby version:
rbenv install 3.3.5
- List all installed versions:
rbenv versions
- Check the active version:
rbenv version
- Uninstall a version:
rbenv uninstall 3.3.4
Global and Local Versions
One of the best things about version managers is how easily you can specify different versions in different contexts. When using rbenv
, you have two scopes:
- Global: for your entire machine
- Local: for specific projects (i.e. scoped to a directory)
My preferred setup is to use the system
version (the one shipped by your OS or installed using the OS package manager) globally, while keeping project-specific versions local:
# Set the machine-wide default
rbenv global system
# Set project-specific version
cd myproject && rbenv local 3.3.5
Managing Gems
Most of the languages I usually work with use the same tool to install global development tools or to manage project dependencies (e.g. go install
/go get
or npm install -g
/npm install
).
Ruby, however, maintains a clearer separation of concerns, with the two main actors being RubyGems (gem
) and Bundler (bundle
).
RubyGems
RubyGems is Ruby's built-in package manager that lets you download and install gems, which are packaged Ruby applications or libraries. When you run gem install rails
, you're telling RubyGems to fetch the Rails framework from rubygems.org (the central repository) and install it on your system. These gems become available globally on your machine, similar to installing it from your OS package manager.
RubyGems manages individual gems in isolation, which works well for simple use cases. However, as applications grew more complex, different projects needed different versions of the same gems. This is where Bundler enters the picture.
Bundler
Bundler is the project-level dependencies manager. Imagine you're working on two Ruby projects: one uses Rails 6.1 and another needs Rails 7.0. Without Bundler, this would be nearly impossible to manage with RubyGems alone. Bundler lets each project specify exactly which gem versions it needs in a file called Gemfile
. When you run bundle install
, Bundler reads this file and creates a precise snapshot of all dependencies (including dependencies of dependencies) in Gemfile.lock
.
Using Them Together in 2024
In modern Ruby development, you'll use both tools, but in different ways. RubyGems is typically used to install development tools you want available system-wide, like:
gem install rails # Installing the Rails CLI
gem install ruby-lsp # Installing a Ruby language server
gem install foreman # Installing a process manager
Meanwhile, Bundler manages the gems that your actual Ruby applications depend on. You'll primarily interact with it through:
bundle install # Install all dependencies specified in Gemfile
bundle update # Update dependencies to their latest allowed versions
bundle exec # Run commands in the context of your project's gems
Both gem
and bundler
are shipped together with Ruby and you should not be required to do anything else to have them on your system.
RubyGems Cheatsheet
Now that you have a version manager, a recent version of Ruby, and gem/bundle
to manage your tools and dependencies, you should be ready to start developing with Ruby.
As a final note, here's a list of useful gem
commands that I need often but always forget:
Install Gems
Gems can be installed with gem install <name>
that will also pull in the gem dependencies
gem install bundler
gem install rails
When using gem
, remember that gems are installed only for the currently active Ruby version, typically located at ~/.gem/ruby/${ruby_version}$/gems/
.
Update Gems
You can get a list of gems that have updates available with:
gem outdated
To update a gem, run:
gem update <name>
This will take care of updating the gem and all its dependencies.
Warning: gem outdated
and gem update
will include also the system gems installed externally (e.g. via pacman
). Make sure to always specify the name of the gem you want to update to avoid undesired effects on your system gems.
Cleanup Gems
When you update a gem, the old version of the gem is not automatically removed, both versions are kept installed. If you want to clean it up, run:
gem cleanup <name>
to remove all old versions of that gem, or:
gem uninstall <name> --version <version>
to remove just a specific version.
Gem Dependencies
You can list all the dependencies of a gem with:
gem dependency <name>
Similarly, you can list all the gems that depend on a specific gem with:
gem dependency <name> --reverse-dependencies