タイトルは釣りです。
主語が大きすぎてちょっとドキドキしてます。では、タイトル通りの話をしていきます。
結論
- 結論から言うと、 Ruby の環境が 汚れるからです
gem install xxx
コマンドは基本的に Ruby の環境にインストールされることになります- ですので、Ruby が状態を持つことになり、冪等性(べきとうせい)に欠けてしまいます
bundler
という便利な仕組みがある上では、gem install xxx
を実行するシチュエーションは限定的になると思います
開発環境構築のジレンマ
開発環境を構築するにあたって、いろんな方法があります。
画一された手段がないというのはメリットでもあり、デメリットでもあります。 (自由性という意味で)
ですが「よくわからないけど、Qiita に載っていて、それが上手くいったからその手順でいいや」というのは問題です。
OSS で公開されているソフトウェアは用途に特化した形で公開されています。それを上手く活用する方法を自分なりに示したいと思います。
具体例
例えば、こういった記事があります
「(Ubuntu)Ruby on rails 6.0 環境構築」
注意点ですが、 この記事が悪いということではなく、こういった手順は私は踏まないという話なだけです。
じゃぁ、貴方はどうやるの?
私は Rails プロジェクトを構築する際には以下のような手順を踏みます。
環境は Ubuntu Linux を前提とします。
Ruby が無い状態から開始します。ほぼほぼ「(Ubuntu)Ruby on rails 6.0 環境構築」と同一ですが、順番が異なります。
前準備
# apt パッケージの情報を最新にするsudo apt update -y# Ubuntu にインストールされているソフトウェアを最新にするsudo apt upgrade -y# Ruby のビルドに必要なパッケージを apt 経由でインストールするsudo apt install build-essential -ysudo apt install-y libssl-dev libreadline-dev zlib1g-dev
# sqlite3 を利用する場合、sqlite3 に関するライブラリをインストールしておくsudo apt install libsqlite3-dev
# PostgreSQL の場合には下記コマンドを実行sudo apt-get install postgresql-common
sudo apt-get install libpq-dev
# MySQL or MariaDB の場合には下記コマンドを実行sudo apt-get install libmysqlclient-dev
Rubyをインストール
# rbenv(パッケージ管理ツール)をインストール
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
# 環境変数にPathを設定echo'export PATH="$HOME/.rbenv/bin:$PATH"'>> ~/.bashrc
echo'eval "$(rbenv init -)"'>> ~/.bashrc
# シェルを再起動exec$SHELL-l# ruby-buildをインストール
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
# Rubyをインストール
rbenv install 2.6.2
rbenv global 2.6.2
# bundler コマンドを gem としてインストールする
gem install bundler
ここまでで Ubuntu Linux に ruby
コマンドと gem
コマンド、 bundler
コマンドがインストールされた状態になりました。
Ruby on Rails で開発を始めるにはまだかかります。
ですが、この状態でしたら、 Ruby のプログラムを書き始める状態までは完了しています。
ここから手順が異なります
次に Rails 6 以降で必要になった Node.js をインストールします。
# node.js, npmをインストールsudo apt install-y nodejs npm
# n packageをインストールsudo npm install n -g# n packageを使ってnodeをインストールsudo n stable
# 最初に入れた古いnode.js, npmを削除sudo apt purge -y nodejs npm
# 再ログインexec$SHELL-l# yarn packageをインストールsudo npm install yarn -g# node.js のバージョンが最新か確認
node -v
この手順を経ることで、Ubuntu Linux 上に ruby
(2.6.2) と gem
コマンド、 node
、 yarn
コマンドがインストールされました。
ここで一息入れます。
これらの準備が整うことで Rails 6 を動かす前準備ができたことになります。
次に自分が作りたいプロジェクトのディレクトリを作成し、Rails のセットアップを行います
# 自分が作成するプロジェクトのディレクトリを作成mkdir example_project
# 作成したディレクトリに移動cd example_project
# bundle init を実行して Gemfile ファイルを作成
bundle init
# 作成された Gemfile を編集して「# gem 'rails'」の部分をコメントインする# 「# gem 'rails'」となっている箇所を#(シャープ)を消して「gem 'rails'」という形にする
gedit Gemfile
# rails をインストールするために bundle install
bundle install--path vendor/bundle
# rails new コマンドを実行して、rails に関する gem をまとめてインストールする
bundle exec rails new
(ここで、「上書きしますか?」的な英文メッセージが表示されるので「Y」を入力)
これらの手順を踏むことで、 Rails が利用できるようになります。
bundle exec rails s
解説
どういう状態になったかを適宜解説していきます
まず、 「前準備」であるライブラリを入れた状態を図として示します
これらは Linux 上にライブラリがインストールされた状態です。これだけでは、 Ruby コマンドの実行はできません (Ruby がインストールされていないので当たり前ではありますが)
「Rubyをインストール」の状態では、以下の状態になります
「Ubuntu Linux にインストールされたパッケージ」のライブラリを元に ruby と gem コマンドがインストールされます。bundler コマンドがある理由は gem install bundler
をコマンドで bundle
コマンドをインストールしているからです。
次に「Node.js」をインストールした状態を示します。
点線で示したのは sudo apt purge -y nodejs npm
コマンドで削除しているためです。
この状態で ruby
, gem
, bundler
, node
, npm
, yarn
コマンドが実行できる状態です。
意識したいポイントとしては、Ruby に関して言えば ruby
, gem
, bundler
コマンドのみ実行可能で、 JavaScript においては node
, npm
, yarn
コマンドが実行できる状態である、というだけです。
次に「自分が作りたいプロジェクトのディレクトリを作成し、Rails のセットアップを行う」という状態を示します。
はい、これで vendor/bundle に プロジェクトに必要なライブラリがインストールされたことになります。
これだけだと対比が分かりづらいと思うので、gem install rails
を実行したケースを示します。
強調したいため赤字で示しました。
ここで言いたいこととしては、 rails
コマンドを実行する rails の gem と 「vendor/bundle ディレクトリ以下 rails 関連の gem が格納される」のバージョンが異なる可能性があるということです。
こういった状態は「ruby にインストールされている特定のバージョンの gem と vendor/bundle
以下にインストールされている gem のバージョンが一致しないことには、完全な再現はできない (冪等性(べきとうせい)がない)」という状況を生み出し得るということです。
一方、先述した方法(gem install rails
を用いない方法) では、「Ubuntu Linux の HOME ディレクトリ以下に設置されたプログラム類」には依存しません。
ですので、 bundler
コマンドを有効活用して、特定のディレクトリ配下にプログラムに必要なライブラリをインストールするようにし、「できる限り Ruby 標準の gem の環境はシンプルに保つ」ということをすると、快適な Ruby の生活ができると思います。
(とはいえ、このお話は恐らく、 Python などパッケージ管理システムを持っているエコシステムでは同じ話が適用できますが)
ですので、きちんと 各コマンドが何の役割を担当していて、どういったことに適するかの意味を理解して実行することが大切だと思います。
勢いで書いているため、乱筆乱文お許しください。
蛇足
- Ruby on Rails の環境を構築するのに、なんで Node.js をインストールしなきゃいけないんだ!という話
- Rails 6 から webpacker というものが標準になりました
- webpacker は node.js のエコシステムである yarn を利用することが必須になります
- 一つの言語で完結しないのは微妙感がありますが、結局 JS 関連で悩むことになるよりも、Node.js のエコシステムに乗っかってしまった方が長期的に考えると幸せになる、ということだと個人的には解釈しています。