【学習アウトプット1】Rails環境構築 (Vagrant&VirtualBox使用)

# 目的
Railsの再現性の高い環境構築を解説します。

もはや何百番煎じかわからないほど語られている内容ではありますが、これだけ情報のある現時点でも構築に行き詰まってにっちもさっちもいかなくなる方がteratailなどに散見されております(特にsqlite3周りが多い印象です)。また今年の2月に入ってLinux版Homebrew, LinuxbrewがHomebrewに統合されました。これによりパッケージの導入が簡単になったことを受けて、改めてRails環境構築の方法の１つを提案させていただきたいと思います。

偉そうな書き出しになりましたが、著者は業務未経験のRails初学者になります。本記事の投稿は筆者の理解度深化も兼ねております（むしろそれが主目的）。間違いなどありましたらご指摘いただきたくお願い申し上げます。

# 構築手順概略
1. Vagrant & VirtualBox(CentOS7)による仮想マシン立ち上げ
2. Linuxbrew導入
3. Ruby, rbenv, Railsインストール
4. sqlite3、その他必要なgemインストール
5. Rails server動作確認（＝環境構築完了）

# 1.Vagrant & VirtualBox(CentOS7)による仮想マシン立ち上げ
再現性高く構築を達成するために、ホストOSの既存環境によるばらつきの影響を受けない仮想マシンを立ち上げます。VagrantとVirtualBoxを用います。

## Vagrantインストール
公式HP https://www.vagrantup.com/downloads.html からmacOS版のVagrantをダウンロードし、インストール

## VirtualBox追加
ターミナル上で`vagrant add box centos/7`と入力し、CentOS7の公式Boxを新規追加。providerを選択するよう指示が出るので`3) virtualbox`を選択

```
$ vagrant box add centos/7
==> box: Loading metadata for box 'centos/7'
    box: URL: https://atlas.hashicorp.com/centos/7
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) hyperv
2) libvirt
3) virtualbox
4) vmware_desktop

Enter your choice: 3
==> box: Adding box 'centos/7' (v1708.01) for provider: virtualbox
    box: Downloading: https://vagrantcloud.com/centos/boxes/7/versions/1708.01/providers/virtualbox.box
==> box: Successfully added box 'centos/7' (v1708.01) for 'virtualbox'!
```
`vagrant box list`入力とするとbox一覧が出るので, `centos/7`が追加されていることを確認

## Vagrantディレクトリ&vagrantfile作成
任意のディレクトリで`vagrant init centos/7`を入力。


```
$ vagrant init centos/7
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read(略)
```
## 接続先の3000番ポート解放（重要！）
vagrantfileに以下の行を追加して保存。これによりゲスト、ホストの3000番ポートを空ける&IPアドレスが割り当てられる

```
25  # NOTE: This will enable public access to the opened port
26  # config.vm.network "forwarded_port", guest: 80, host: 8080
27  config.vm.network :forwarded_port, guest: 3000, host: 3000　<=これ
```

```
34  # Create a private network, which allows host-only access to the machine
35  # using a specific IP.
36  config.vm.network :private_network, ip: "192.168.33.10"　<=これ
```

参考記事：[Vagrant(CentOS7) + Rails環境でホストのブラウザからサーバ接続できなかった時の対処](https://qiita.com/Ago0727/items/325df5e39e3406fa16d2)

## box起動&接続
`vagrant up`でboxを起動

```
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'centos/7'...
```

`vagrant ssh`でboxに接続する（仮想マシンに入り込む）。

```
$ vagrant ssh
[vagrant@localhost ~]$ 
```

以降の作業は仮想マシン内で行う


# 2. Linuxbrew導入
Linuxbrewとは：
詳しい解説は他の記事に譲ります。筆者のざっくりした認識で述べると、パッケージの依存関係などの小難しい部分をよしなにしてくれて使えるようにしてくれるソフトです。後述するgit最新版へのアップデートやrbenvのインストールがとても簡単になります。筆者はLinuxbrewを使わずに一度gitを最新版にしようとして、最終的にできましたがとても大変でした。
（公式：https://docs.brew.sh/Homebrew-on-Linux)
公式に載っている手順をそのまま使い、導入します。

## 周辺ツールのインストール
`sudo yum groupinstall 'Development Tools' && sudo yum install curl file git`を入力。

```
[vagrant@localhost ~]$ sudo yum groupinstall 'Development Tools' && sudo yum install curl file git
Failed to set locale, defaulting to C
Loaded plugins: fastestmirror
There is no installed groups file.（略)
```
## Linuxbrewのインストール
`sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"`を入力（結構時間かかります）

```
[vagrant@localhost ~]$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
==> Installing Ruby to /home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/vendor
（略、途中からビールの絵文字が出てきます）
```
## PATHを通す
2.の完了後、PATHが通ってないことに警告が出るので通す。下記のコマンドを上から順に入力。

```
test -d ~/.linuxbrew && eval $(~/.linuxbrew/bin/brew shellenv)
test -d /home/linuxbrew/.linuxbrew && eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
test -r ~/.bash_profile && echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.bash_profile
```

## インストールチェック
`brew install hello`で試運転

```
[vagrant@localhost ~]$ brew install hello
==> Downloading https://linuxbrew.bintray.com/bottles/hello-2.10.x86_64_linux.bo
######################################################################## 100.0%
==> Pouring hello-2.10.x86_64_linux.bottle.tar.gz
🍺  /home/linuxbrew/.linuxbrew/Cellar/hello/2.10: 52 files, 237.7KB
```

以上でLinuxbrewの導入は完了です。

# 3.Ruby, rbenv, Railsインストール
おなじみのバージョン管理ソフトであるrbenvを使ってrubyの最新安定板をインストールします。加えてRailsの最新安定板をインストールします。

## rbenvインストール
`brew install rbenv`を入力。これまた時間がかかります。

```
[vagrant@localhost ~]$ brew install rbenv         
==> Installing dependencies for rbenv: gdbm, berkeley-db, perl, autoconf, pkg-config, ruby-build, libyaml, readline and ruby
```
（注）よく一緒にインストールされるruby-buildは、rbenvのインストール時に同梱される模様です。試しにインストールすると以下のように警告されます。インストールはrbenvだけでよさそうです。

```
[vagrant@localhost ~]$ brew install ruby-build
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> Updated Formulae
bundletool                 librealsense               speedtest-cli

Warning: ruby-build 20190130 is already installed and up-to-date
To reinstall 20190130, run `brew reinstall ruby-build`
```

その後ターミナルを開くたびにrbenvが初期化されるように、以下のコマンドを入力します。

```
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
```
(正直このコマンドの意図を理解できておりません。なぜrbenvを毎回初期化する必要があるのか？わかる方いらっしゃいましたらご教示いただけると嬉しいです。）

## Rubyインストール
`rbenv install 2.6.1`を入力して新しいRubyをインストールします。（最新安定板は執筆時点で2.6.2でしたが、rbenvのリストにありませんでした。。。）これも時間かかります。

```
[vagrant@localhost ~]$ rbenv install 2.6.1
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:（略)
```

完了したら`rbenv versions`で追加確認。2.6.1があることを確認して`rbenv global 2.6.1`でバージョン変更。`ruby -v`でバージョン確認。

```
[vagrant@localhost ~]$ rbenv versions
* system (set by /home/vagrant/.rbenv/version)
  2.6.1
[vagrant@localhost ~]$ rbenv global 2.6.1
[vagrant@localhost ~]$ ruby -v
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
```

## Railsインストール
`gem install rails --version "5.2.2" -N`でRailsの最新安定板5.2.2をインストール。末尾の-Nはドキュメントの生成を省略するオプションです。

```
[vagrant@localhost ~]$ gem install rails --version "5.2.2" -N
Fetching concurrent-ruby-1.1.5.gem
Fetching nokogiri-1.10.1.gem
Fetching crass-1.0.4.gem（略）
```

インストールが終わったら適当なディレクトリを作り、その直下で`rails new`コマンドを入力。

```
[vagrant@localhost ~]$ mkdir test
[vagrant@localhost ~]$ ls
test
[vagrant@localhost ~]$ cd test
[vagrant@localhost test]$ rails new testapp
      create  
      create  README.md （略）
~~
An error occurred while installing sqlite3 (1.4.0), and Bundler cannot
continue.
Make sure that `gem install sqlite3 -v '1.4.0' --source 'https://rubygems.org/'`
succeeds before bundling.
```

早速sqlite3でエラーがでています。ここから修正する作業に入ります。

# 4. sqlite3、その他必要なgemインストール
現段階で無理やり`rails s`をすると以下のようなエラーが確認されるかと思います。

```
[vagrant@localhost testapp]$ rails s
Could not find gem 'sqlite3' in any of the gem sources listed in your Gemfile.
```

ただ、ちゃんとgemfileにsqlite3はあります。それならと`bundle update`とか`bundle install`をしても以下のようなエラーが出ます。

```
An error occurred while installing sqlite3 (1.4.0), and Bundler cannot
continue.
Make sure that `gem install sqlite3 -v '1.4.0' --source 'https://rubygems.org/'`
succeeds before bundling.
```
sqlite3をインストールする必要がありそうです。しかしエラーの指示通り`gem install sqlite3 -v '1.4.0' --source 'https://rubygems.org/'`を試してもエラーが吐かれます。

```
[vagrant@localhost test]$ gem install sqlite3 -v '1.4.0' --source 'https://rubygems.org/'
Building native extensions. This could take a while...
ERROR:  Error installing sqlite3:
	ERROR: Failed to build gem native extension.
```

困りました。

## sqlite3のインストール
`brew install sqlite3`で解決できました。

```
[vagrant@localhost test]$ brew install sqlite3
==> Downloading https://linuxbrew.bintray.com/bottles/sqlite-3.27.1.x86_64_linux
Already downloaded: /home/vagrant/.cache/Homebrew/downloads/b14ee0adb13d26ca99054ac9698cc768be82b5747a562ccad0d58d48dd417570--sqlite-3.27.1.x86_64_linux.bottle.tar.gz
==> Pouring sqlite-3.27.1.x86_64_linux.bottle.tar.gz
🍺  /home/linuxbrew/.linuxbrew/Cellar/sqlite/3.27.1: 12 files, 4.4MB
```

## Gemfile修正->Bundlerで反映
ここでGemfileのGemを一括反映させます。でもその前に以下の`gem 'therubyracer'`を追加しましょう。

```
15 gem 'uglifier', '>= 1.3.0'
16 # See https://github.com/rails/execjs#readme for more supported runtimes
17 # gem 'mini_racer', platforms: :ruby
18
19 gem 'therubyracer'　<=これ
```
これを入れずに`rails s`すると以下のエラーが発生します。

```
/home/vagrant/.rbenv/versions/2.6.1/lib/ruby/gems/2.6.0/gems/execjs-
2.7.0/lib/execjs/runtimes.rb:58:in `autodetect': Could not find a JavaScript 
runtime. See https://github.com/rails/execjs for a list of available runtimes. 
(ExecJS::RuntimeUnavailable)
```
参考記事：[rails sコマンド実行時に「Could not find a JavaScript runtime.」とエラーが出る場合の対処法](https://qiita.com/azusanakano/items/771dc9919f347de061d7)

`gem 'therubyracer'`を入れてから`bundle update`,`bundle install`を入力します。

```
[vagrant@localhost testapp2]$ bundle update
略
[vagrant@localhost testapp2]$ bundle install
略
Bundle complete! 19 Gemfile dependencies, 82 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
```

# 5.Rails server動作確認
満を辞して`rails s`です。エラーが起きる人は`gem 'therubyracer'`を入れ忘れてないかなど今一度確認を。

```
[vagrant@localhost testapp2]$ rails s
=> Booting Puma
=> Rails 5.2.2.1 application starting in development 
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.6.1-p33), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
```

http://127.0.0.1:3000/ へアクセス

サーバーが走っているのにアクセスしても繋がらない方は1章でのでの3000番ポート開放がうまくいっていないかもしれません。ctrl+cでサーバーを止め、一度`exit`で仮想マシンから抜けた後、`vagrant reload`で再起動してからもう一度アプリディレクトリで`rails s`してみましょう。

繋がった方、おそらく以下のようなエラー画面が表示されていると思います。

Puma caught this error: Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile. (LoadError)

[Railsを始めてsqlite3まわりのエラーで躓いている人たちへ](https://qiita.com/Kta-M/items/254a1ba141827a989cb7)によると、現行のRailsが受け付けるsqlite3のバージョンは1.3.6〜1.4.0未満とのことです。sqlite3の最新版は1.4.0なので、バージョンを指定しないと弾かれてしまいます。

## Gemfile修正 -> 再度rails s
二度手間で恐縮ですが上記状況を周知したくこのような構成にしました。改めてGemfileを以下のように修正し、sqlite3のバージョンを指定します。

```
# Use sqlite3 as the database for Active Record
gem 'sqlite3','~> 1.3.6'
```
`bundle update`,`bundle install`してGemを反映。
その後`rails s`してhttp://127.0.0.1:3000/ へ。

<img width="567" alt="スクリーンショット 2019-03-14 17.41.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/326593/4401fb9d-76fb-0c35-0be2-6f142d4bb8f8.png">

# おわりに
改めて文章に起こすとやっぱり駆け出しにはしんどいなと思われる仮想マシンでの環境構築ですが、Linuxbrewのおかげでだいぶ使いやすくはなったのではないかと思います。Railsチュートリアルをcloud9などで終わらせた方々が、自前で環境構築する際の一助になれば幸いです。