Tips

MacでのRubyのBundler自体のバージョン切替え

MacでRubyを使った開発していると、プロジェクトごとに使われているBundlerのバージョン自体が違うことがあります。その際の対策をお伝えします。

プロジェクトごとに使われるBundlerのバージョンが違う

プロジェクトごとに生成されるGemfile.lockに使われたBundlerのバージョンが記載されます。

Gemfile.lockで指定されたBundlerのバージョンと違うBundlerで bundle install を実行するとエラーとなりGemがインストールできません。

なので、プロジェクトごとに使われているBundlerのバージョンが異なっていれば、Macに複数のBundlerをインストールし、都度使い分ける必要が出てきます。

同じような悩みは以下のページでも記載されています。

bundler 自体をローカルにインストールする方法

MacでのRuby開発環境の考え方。rbenvを使おう。

答えの前に、まずMacでRubyを使った開発を行う環境構築について簡単にご説明します。

当方はMacに何かしらソフトウェアをインストールする場合は、Homebrewを使うことを推奨してきました。

Homebrewとは?本質的な価値を解説。何ができる?メリットは?Macで何かをインストールするための記事でよく紹介されるHomebrewって一体なんなのでしょうか?検索して調べてもわかったようでわから...

しかし、RubyをMacにインストールする場合は違います。RubyをMacに入れる場合、rbenvというRubyを管理するツールをHomebrewでインストールし、rbenvを使ってRubyをインストールするのがおすすめです。

複数のRubyの開発プロジェクトに関わっていると、それぞれのプロジェクトで使われているRubyのバージョンが違うということはザラにあります。HomeBrewだと、以下で説明したように、過去のバージョンをインストールすることはできなくはないですが、一手間かかりますし、気軽に切り替えることができません。

Homebrewで過去バージョンのアプリをインストールする方法Homebrewで何かをインストールする場合、デフォルトでは最新のバージョンがインストールされます。訳あって過去のバージョンのものをイン...

rbenvならバージョン指定してRubyをワンコマンドでインストール、切り替えもできますし、ディレクトリごとに別のバージョンのRubyを使うことも簡単にできます。

BundlerはRubyのバージョンごとにグローバルにインストールされる

次に、Rubyのプロジェクトごとに使われる多くのGemと言われるライブラリの管理についてご説明します。

通常GemはRubyのバージョンごとにインストールされます。例えば、MacにrbenvによってRubyの2.4.1、2.4.2の二つのバージョンがインストールされているとします。すると、2.4.1と2.4.2のそれぞれがGemをインストールするディレクトリをグローバルに持ち、そこにインストールされるようになります。

これだと問題が起こります。同じRubyのバージョンを使っているプロジェクトは全て同じGemのバージョンを使わないといけなくなります。プロジェクトごとにGemのバージョンを変えられないということになります。

それを解決するのがBundlerです。BundlerはGemの管理のスタンダードとなっています。Bundlerを使うと、プロジェクトごとのディレクトリ配下にGemをローカルにインストールすることが可能となります。

なので、Gemは基本的にグローバルにはインストールせず、全てプロジェクトごとにローカルにインストールする開発スタイルがおすすめです。重複するGemもあるかもしれませんが、こちらの方がマシンに依存せずプロジェクト内に閉じて管理できるのでわかりやすいです。

実はBudler自体もGemです。しかし、BundlerはBundler自身によって管理することができないので、Budlerだけはグローバルにインストールするしかありません。つまり、Rubyのバージョンごとにインストールします。

ここで出てくるのが冒頭で紹介した問題です。先のページの質問者さんが考えるようにBundler自体もローカルにインストールできればいいのですがそれはできません。

Bundlerを複数インストールし実行時に指定する

解決策は以下となります。

Rubyのバージョンごとに複数のGemをインストールすることは可能です。そして、Gemは実行時にバージョンを指定することが可能です。

なので、一つのRubyのバージョンに複数のBundlerをインストールします。以下のようにバージョンを指定して複数インストールしてみます。

すると、以下のように複数のBundlerのバージョンがインストールされたことが確認できます。

バージョンを指定する方法は次のように _でバージョン番号を挟んで指定できます。

対象のRubyのプロジェクトのディレクトリに移動し、

とGemfile.lockで指定されたバージョンを指定すると無事にGemをインストールできます。

上位のバージョンを使っておけばOKなのかも

冒頭のエラーは2.1.4のBundlerが求められているプロジェクトで1.17.2で実行した場合です。実は、この状況で2.2.15で実行した際は、正常に実行できました。

つまり、もしかしたら求められているものより上位のバージョンで実行すれば問題ないのかもしれません。

ここまで書いて今更気づいたのですが、そうするとBundlerに関しては、バージョンの使い分けなどを考える必要はなく、常に最新のバージョンを入れておけば良いのかもしれません。Homebrew、rbenvもそうですが、このような管理ツールはなるべく互換性を維持しながらアップデートされていくからです。しかし、どこかのタイミングでツールの構成がガラッと変わって互換性が完全には維持されない可能性も無くはないので、上述した対処策は知っておいて損はないでしょう。

また、Bundlerは bundle installだけではなく開発しているプログラム自体を実行する際の、 bundle execでも使われます。プログラムの実行環境がちょっとでも変わると気持ち悪い気もするので、以下のようにBundler自体のバージョンもしっかり指定しておくというのはアリだと思います。

ちなみに、 bundle _2.1.4_ exec の部分が長くて毎回入力するのが面倒!って思う方はお使いのシェル(zsh)などのアライアスを使って短くしちゃうのもありですね。

.zshrcにコマンドエイリアスを定義してbundle execをbeと省略可能にする方法

ただ、これだと、どのプロジェクトでも2.1.4固定になってしまうので、direnvなどのツールと組み合わせてプロジェクトごとに自動で切り替えてくれるようにしてみてもいいかもしれません。

[mac]zshでdirenvを使用する