rbenv と bundler で Ruby のバージョンと gem を管理する方法


こんにちは Masuyama です。

一つの環境で Ruby の開発、gem のインストールを行っていると、アプリケーションごとの依存関係の差異によるエラーに苦しむことになります。
そこで今回は rbenv と bundler を用い、Ruby のバージョンと gem を管理する方法をご紹介します。

# 開発環境の前提

rbenv はインストールされていること

念のため、参考となりそうな記事をご紹介しておきます。

- [Mac の場合](https://qiita.com/TakahashiKat/items/7a45bbd5d0e675c1de3f)
- [Windows の場合](https://qiita.com/ktpnobu/items/fa0c198ee14b9875817a)

# Ruby バージョンの管理

rbenv を用いて特定バージョンの Ruby をインストール、および管理していきます。
今回は 2.7 系をインストールしたいと思います。

### rbenv とは

rbenv とは、Ruby のバージョンを管理し、複数のバージョンを切り替えて使用できるようにするツールです。
使っている環境全体 (global) のバージョンだけでなく、ディレクトリごと (local) のバージョンを設定することもできます。

### 特定バージョンの Ruby をインストール

rbenv でインストール可能な Ruby のバージョンをまず確認します。
rbenv install コマンドに -l オプションを付けると、安定バージョンかつ最新のものが表示されます。

```
$ rbenv install -l
2.6.7
2.7.3
3.0.1
...
```

2.7 系の中では 2.7.3 が最新であると分かったので、これをインストールします。

```
$ rbenv install 2.7.3
```

結構時間がかかるのでしばらく待機します。
完了したら、rbenv versions コマンドでインストールしたものの一覧を確認します。
※下記の例のように、既にインストールしたバージョンがあると表示は変わります

```
$ rbenv versions
  system
  2.6.6
* 2.7.0 (set by /Users/masuyama/.rbenv/version)
  2.7.3
```

「＊」マークは現在適用されている Ruby のバージョンです。
今回ですとバージョン 2.7.0 が適用されている状態であり、先程インストールしたバージョン 2.7.3 はまだ適用されていません。

### 特定バージョンの Ruby を適用

それでは作業用のディレクトリを指定して、その中で使う Ruby バージョンを設定し、2.7.3 を適用していきます。
特定のディレクトリ内だけに適用するには rbenv local コマンドを使います。

```
$ mkdir ruby_pj
$ cd ruby_pj
$ rbenv local 2.7.3
$ rbenv versions
  system
  2.6.6
  2.7.0
* 2.7.3 (set by /Users/masuyama/ruby_pj/.ruby-version)
```

実際に ruby コマンドを叩いてバージョンを確認すると、2.7.3 が適用されていることが分かります。

```
$ ruby -v
ruby 2.7.3p183 (2021-04-05 revision 6847ee089d) [x86_64-darwin20]
```

# gem ライブラリの管理

さて、このディレクトリ内で使う gem もライブラリも個別に管理しましょう。
そのためには bundler という gem を使います。

### bundler とは

bundler は「gem の依存関係とバージョンを管理するためのツール」です。

多くの開発環境では複数の gem を利用しますが、個別の gem がまた別な gem を利用するというケースが多くあり、そういった依存関係を自分で解決するのはかなり大変です。
そこで bundler を使うと、gem の依存関係を解決しながら gem を一括でインストールすることができます。

### bundler をインストール

まずは Bundler をインストールします。

```
$ rbenv exec gem install bundler
$ rbenv rehash
```

ここでポイントとなるのは、gem install コマンド実行時に接頭辞として **rbenv exec** をつけていることです。
これにより **rbenv で適用中の Ruby で実行** していることになるので、このディレクトリに local でセットした Ruby 2.7.3 を使用することになります。

### bundle の設定

はじめに bundle の設定ファイル (Gemfile) の雛形を生成します。
Gemfile を生成するには bundle のサブコマンドである init を使いますが、ここでも rbenv exec コマンドを使うことに注意しましょう。

```
$ rbenv exec bundle init
```

これを実行するとディレクトリ (/ruby_pj) 内に Gemfile という設定ファイルが生成されます。
この Gemfile 内に、インストールしたい gem ライブラリを記載していくことになります。

```
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }

# gem "rails"
```

デフォルトで入っている rails の記述はコメントアウトします。

```
gem "rails"
```

なお、Gemfile 内の gem 情報の書き方に応じ、gem のバージョンを指定することができます。
以下に書き方の例を提示しておきます。

| 記法                    | インストールされるバージョン                                  |
| ----------------------- | ------------------------------------------------------------- | ------------------------------------------------------- |
| gem 'rails'             | 最新のバージョン                                              |
| gem 'rails', '6.0.0'    | バージョンを一意に指定 (6.0.0 を必ずインストールしようとする) |
| gem 'rails', '>= 6.0.0' | 6.0.0 以上の最新                                              |
| gem 'rails', '~> 6.0'   | 6.0 以上、7.0 未満の最新 (メジャーバージョンを維持)           | 6.0.0 以上、6.1.0 未満の最新 (マイナーバージョンを維持) |

なお、今回の Gemfile のようにバージョン指定無しの場合は、常に最新版をインストールします。

### bundler で gem をインストール

Gemfile の記載に沿って gem をインストールするには、bundle install コマンドを使用します。

```
rbenv exec bundle install --path=vendor/bundle
```

この時 --path オプションを用いて作業用ディレクトリ配下に gem ファイルをインストールすることがポイントです。
このオプションを付けないと rbenv で指定したバージョンの Ruby そのものに紐付いて gem がインストールされてしまい、結果的に同じバージョンの Ruby を利用する他のプロジェクトに影響を与える可能性があるので注意しましょう。

さて、これで Gemfile 内で唯一指定していた rails の gem の最新版がインストールされているはずなので
rails -v でインストールされたバージョンを確認します。

```
$ bundle exec rails -v
Rails 6.1.4.1
```

この時、同じディレクトリ内に Gemfile.lock というファイルも生成されているはずです。
bundler では依存関係を解決しながら gem をインストールしてくれますが、Gemfile に記載された gem のバージョンや依存関係を解決した結果を Gemfile.lock として保存します。
この Gemfile.lock は bundler が自動で編集するものですので、特別な理由がない限り手動では書き換えないように注意しましょう。

# よく使われる bundle コマンド

他にもいくつかよく使う bundle コマンドがあるので、既に紹介してものも含めて整理しておきます。

| コマンド                     | 実行結果                                                    |
| ---------------------------- | ----------------------------------------------------------- |
| bundle init                  | Gemfile を生成                                              |
| bundle install               | Gemfile (.lock) にかかれている gem パッケージをインストール |
| bundle update [ライブラリ名] | インストール済み gem のバージョンを更新                     |
| bundle list                  | インストール済みの gem の一覧を表示                         |
| bundle exec [コマンド名]     | bundler でインストールされた gem を仕様してコマンドを実行   |

以上となりますが、何かご指摘事項がありましたらコメントいただければと思います。