Welcome to Tony's Notebook

Troubleshooting Ruby Gems

I had a some issues recently with running certain Ruby applications on my system. I'd get weird error messages on startup, or the application couldn't be found at all. I thought I'd put together a few notes on troubleshooting my installation, what the problem was, and how I tracked the issue down.

The problem

I have a couple of Ruby applications I run locally: nexmo-developer and nexmo-oas-renderer which are both packaged as Ruby Gems. I'd been getting a number of weird errors on startup. I'd run bundle and still get issues. In certain circumstances the application could not be found at all. I finally had enough as it was causing a lot of pain trying to keep my Ruby applications running reliably, so I sat down to figure out what was going on. The issue turned out to be due to the interplay between the following:

I'll go through each of these very briefly and explain what they do in very simple terms.

rbenv

rbenv allows you to install and manage multiple versions of Ruby. On a typical Mac setup you have a system Ruby, but most people (including me) leave this well alone and install rbenv so you can easily install and switch between Ruby versions as required. rbenv uses ruby-build to do this. I installed rbenv using brew. There are a few useful commands to use with rbenv:

Command Description
rbenv versions Displays all the installed versions you might have on your system, including the currently selected version (shown by a *).
rbenv install Allows you to install a specific version of Ruby, for example, rbenv install 2.5.8
rbenv global Allows you to set a version of Ruby to be used globally, for example, rbenv global 2.5.8

gem

The gem command allows you to install a Ruby application packaged as a Gem. For example, to install the neocities command line tool you'd type gem install neocities. You can think of this as a "global install". You can see where the Gem has been install to by using gem info <package>, for example:

$ gem info neocities

*** LOCAL GEMS ***

neocities (0.0.15)
    Author: Kyle Drake
    Homepage: https://neocities.org
    License: MIT
    Installed at: /Users/tbedford/.rbenv/versions/2.5.8/lib/ruby/gems/2.5.0

    Neocities.org CLI and API client

You'll notice the Gem is installed in a version-specific location, in this case 2.5.8 (I was running 2.5.8 when I installed this Gem). If for example I switch to Ruby 2.5.7 with rbenv global 2.5.7 and tried to run neocities I'd get the following:

rbenv: neocities: command not found

The `neocities' command exists in these Ruby versions:
  2.5.8

This is important!

If I switch back to 2.5.8 with rbenv global 2.5.8 and run the command again I get:

neocities

  |\---/|
  | o_O |   Neocities 
   \_o_/

  Subcommands:
    push        Recursively upload a local directory to your site
    upload      Upload individual files to your Neocities site
    delete      Delete files from your Neocities site
    list        List files from your Neocities site
    info        Information and stats for your site
    logout      Remove the site api key from the config
    version     Unceremoniously display version and self destruct
    pizza       Order a free pizza

Note you can use the command line to order a free pizza! ;)

By the way, to figure out what version of gem you are running you can enter gem -v. To update the gem command itself (but not the installed packages/gems) use the following:

gem update --system

bundle

OK so there's this thing called bundler. It's a dependency manager for Ruby applications. What is does is it processes a Gemfile in your applications directory, and from that figures out dependencies and makes sure they are installed too. For example, looking at the Gemfile for our api-specification repo we have:

source 'https://rubygems.org'

gem 'nexmo-oas-renderer', '~> 2.1'

This means we require the nexmo-oas-renderer to render specs locally, and the version required is identical to >= 2.1 and < 3.0. So, if you decide you want to install this Gem and its dependencies (of which there are many), you'd enter bundle and the dependencies would be determined and installed along with the main app. Of course these will be installed in a location dependent on the version of Ruby you're currently running. In my case:

$ gem info nexmo-oas-renderer

*** LOCAL GEMS ***

nexmo-oas-renderer (2.1.3)
    Author: Fabian Rodriguez
    Homepage: https://github.com/Nexmo/nexmo-oas-renderer
    License: MIT
    Installed at: /Users/tbedford/.rbenv/versions/2.5.8/lib/ruby/gems/2.5.0

    OpenAPI Specification renderer.

My issue

With multiple versions of Ruby and a various Gems installed for different versions of Ruby using different methods over the last year or so, it was only a matter of time before I ran into problems. For example, gems installed using version 2.5.7 would not longer be available after I switched to 2.5.8. I also installed gems using different methods. For example, some time past I downloaded both Nexmo renderer and Station source repositories and installed them from the source. These would then potentially conflict with versions installed via bundler. To get around this I used gem uninstall to remove all versions. I then reinstalled both using bundler only.

A few commands I found useful:

In closing

My general strategy now for troubleshooting these installs is:

  1. Check version of Ruby is globally correct and make sure you haven't overridden this locally unless necessary
  2. Check I'm using latest versions of bundle and gem
  3. Remove all versions of the problematic app with gem uninstall
  4. In the application directory (where the Gemfile is) run bundle to install the app and its dependencies

Hope this helps!