Bundled gems and not being that smart.
Tags: ruby, bundler, gems, multijson
Published: 2023-03-03 09:13:28

I've spent the past day looking at an issue with what appeared to be because of loosely defined dependencies. I thought perhaps the version of a gem that was being loaded was not the expected one and something very odd was going on, and hell the application I am working on is Ruby 2.6.5 so it might just behave slightly differently and someone fixed something that I've never seen before since then.

I am sure there was some command that could prune installed gems.

```bash
bundle pristine
```

Nope that re-installs the bundled gems afresh. Ok, I can't remember but hell this will do it. This is where all the gems are located on this machine for this Ruby version.

```bash
rl@Robs-MacBook-Pro some_project % bundle show --paths
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/actioncable-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/actionmailbox-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/actionmailer-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/actionpack-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/actiontext-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/actionview-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/activejob-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/activemodel-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/activerecord-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/activestorage-6.0.3.6
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.6
...
```

You Only Live Once.

```bash
rm -rf /Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/
```

Ok that's screwed up a few things, I need bundler back to the version this project is bundled with and re-bundle everything

```bash
gem install bundler -v 2.3.26
bundle install
```

Run the application and erm...application falls over because it can't find `multi_json`. This application does not have multi_json in it at all. It's not in the Gemfile.lock so nothing requires it at all. So why what?

I can follow the failure by sticking `pry` and capturing the backtrace.


It's falling over because `json-schema` requires it. How it's not a dependency of json-schema. If it were it would be in our Gemfile.lock

```bash
bundle show --paths | xargs grep -r multi_json
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/json-schema-3.0.0/lib/json-schema.rb:if Gem::Specification::find_all_by_name('multi_json').any?
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/gems/json-schema-3.0.0/lib/json-schema.rb:  require 'multi_json'
```

#### *`spec/dummy/config/application/rb`*
```ruby
# frozen_string_literal: true

require_relative "boot"

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "rswag"
# require "action_cable/engine"
# require "sprockets/railtie"
# require "rails/test_unit/railtie"

```

It's when `rswag` is required. 

```ruby
begin
  require "rswag"
rescue => e
  binding.pry
  raise
end
```

Ok, that tells me exactly where is required from.

This is it, it's in the `json-schema` gem and it is definitely requiring `multi_json`. And there must be an installed gem for it. So how come it's installed when it isn't?

```ruby
if Gem::Specification::find_all_by_name('multi_json').any?
  require 'multi_json'

  # Force MultiJson to load an engine before we define the JSON constant here; otherwise,
  # it looks for things that are under the JSON namespace that aren't there (since we have defined it here)
  MultiJson.respond_to?(:adapter) ? MultiJson.adapter : MultiJson.engine
end
```

Ok, so I can be smart. But sometimes I am so smart I am stupid. There's the sucker. There is a specification for `multi_json` but there isn't a gem for it. Oh well. Serves me right for deleting stuff I shouldn't have.

```bash
/Users/rl/.asdf/installs/ruby/2.6.5/lib/ruby/gems/2.6.0/specifications/multi_json-1.15.0.gemspec
```

Nuke the specification too and we're good. Hell I might just install `multi_json` and use `oj` for the speed.