Searching through your bundled gems

You've probably been working on a project where someone added a feature from a gem which caused an error, but you had no idea where to find the offending code.

For me, that happened yesterday. Someone had removed a database table without diving in to see what code actually required the table. Unfortunately, this is a rescue project which barely has tests.

Here's a quick summary of what you can do:

ag thethingyouneed `bundle show --paths`

I began writing some acceptance tests to cover our asses and found that when I attempted to delete a user, the test blew up. Deleting a user was completely unrelated to what I actually cared about but it coincidentally happened for my test.

The failure was because I was missing a receipts table. The fact that this table was needed was news to me, so I asked other team members to find out what it was.

"Oh, yeah. Have you rebased onto develop? It was removed."

WTF?! Why? Why would anyone remove a table and not make sure to investigate that no leftover code required it? Unfortunately lazy developers make mistakes.

So I began digging. I knew the requirement for the offending table existed somewhere in our project, but there was no direct reference in our application code.

Bundler must have a way to search through it's gems, right? Wrong.

I found a few pull requests related to this need and realized that it was much simpler than relying on bundler to do the job for me.

Bundler can provide you with all the load paths that it creates with

bundle show --paths

And nix tools like grep or ack can take a collection of paths to search through. I really like using the_silver_searcher however, so that's my go-to tool. It's super fast.

All I needed to do was pass that collection of paths to ag and I had what I needed.

ag receipts `bundle show --paths`

Then I was on my way and found that we were using a gem that provided an acts_as_messagable method that expected a receipts table to exist was used in one of our models and was no longer needed.

There are 3 lessons here.

First, you can compose things with unix tools and I don't need Bundler to do the entire job for me.

Second, you really should be writing tests. It's the presence and execution of a test that found this bug for me.

Third, always make sure you properly clean up your project. Consider the impact of your laziness on the rest of the team. An ounce of prevention is worth a pound of cure.

Get a FREE sample chapter

Get a sample chapter of Clean Ruby and you'll be added to my periodic newsletter of helpful Ruby tips.