Vagrant で Ruby on Rails 4 の環境構築

# はじめに
今回、諸事情により Python 使いの人間が
Ruby on Rails 4 (+ Ruby) 世界に入門することになったので、
そのためのテスト環境構築を行う。

今回は仮想環境上にテスト環境を構築する。
仮想環境として、VirtualBox + Vagrant を用いる。

Ruby は RVM (Ruby のバージョンを管理するためのツール) で管理する。
この記事を作成している時点で最新版の2.1系をインストールする。

また、Rails 自身と Rails に必要な各種ライブラリ (Gem) は Bundler で管理する。
この記事を作成している時点で最新の4.2系をインストールする。

# 仮想マシン周りの構築
## VirtualBox のインストール
[https://www.virtualbox.org/wiki/Downloads](https://www.virtualbox.org/wiki/Downloads) から最新版をインストール。
仮想環境の作成は Vagrant から行う。

## Vagrant のインストール
[http://www.vagrantup.com/downloads](http://www.vagrantup.com/downloads) から最新版をダウンロードしてインストール。

## 仮想マシンの作成
今回は CentOS6.5 の イメージファイルを使う。
また、仮想環境の作成先ディレクトリは `~/projects/centos6_rails4` とした。

```
$ vagrant box add centos6.5 https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box
$ mkdir ~/projects
$ mkdir ~/projects/centos6_rails4
$ cd ~/projects/centos6_rails4
$ vagrant init centos6.5
```

Vagrantfileの下記の部分を編集してメモリの割り当てを4GBに増やす

``` ruby:Vagrantfile 
config.vm.provider "virtualbox" do |vb|
  #   # Don't boot with headless mode
  #   vb.gui = true
  #
  #   # Use VBoxManage to customize the VM. For example to change memory:
  vb.customize ["modifyvm", :id, "--memory", "4096"]
end
```

また Rails で使用する3000番ポートのポートフォワーディング設定も行う。

``` ruby:Vagrantfile 
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  # ...

  # config.vm.network "forwarded_port", guest: 80, host: 8080
  config.vm.network :"forwarded_port", guest: 3000, host: 3000

  # ...
end
```

その後、以下のコマンドを実行すると仮想環境にログインできる。

```
$ vagrant up
$ vagrant ssh
```

仮想環境から抜ける際は、ssh 接続を閉じればOK。

```
$ vagrant halt
```

で仮想マシンの電源を落とせる。
再び仮想環境を起動する際は仮想マシンをインストールしたディレクトリに移動し、
`vagrant up` -> `vagrant ssh` とすればよい。

# Rubyの環境構築
## RVM の導入
Ruby は RVM を使用してバージョンの管理を行う。
下記URLを参考にしつつ作業を進める。
[https://rvm.io/rvm/install](https://rvm.io/rvm/install)

下記のコマンドを実行していく。

```
$ gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
$ sudo yum install -y emacs # 自分の環境に必要なものを先に入れておく
$ sudo yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison iconv-devel
$ curl -L https://get.rvm.io | bash -s stable
$ source .profile
```

バージョンの確認。

```
$ rvm -v
rvm 1.26.7 (latest) by Wayne E. Seguin <wayneeseguin@gmail.com>, Michal Papis <mpapis@gmail.com> [https://rvm.io/]
```

Ruby 2.1.x をインストール。

```
$ rvm install 2.1
$ ruby -v
ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-linux]
$ ruby -e 'puts("Hello, world!")'
Hello, world!
```

RVM で Ruby 2.1 がインストールできた。

# Rails のインストール
公式等の説明のようにそのまま

```
$ gem install rails
```

すると、システム全体に依存関係の Gem がインストールされてしまう。
今回は Rails 自体もプロジェクト毎に Bundler で管理する。

```
$ mkdir ~/projects
$ mkdir ~/projects/sample_rails_project # sample_rails_project の部分は作成するプロジェクト名に
$ cd ~/projects/sample_rails_project
$ bundle init
Writing new Gemfile to /home/vagrant/project/sample_rails_project/Gemfile
```

作成されたGemfileを以下のように記述。

``` ruby:Gemfile
# A sample Gemfile
source "https://rubygems.org"

gem "rails"
```

デフォルトの SQLite3 用のパッケージを先に導入しておく。

```
$ sudo yum -y install sqlite-devel
```

Bundler で各種 Gem をプロジェクトのディレクトリ以下にインストールし、
Rails プロジェクトを作成。

```
$ bundle install --path vendor/bundle
$ bundle exec rails new .
       exist 
      create  README.rdoc
      create  Rakefile
      create  config.ru
      create  .gitignore
    conflict  Gemfile
Overwrite /home/vagrant/project/sample_rails_project/Gemfile? (enter "h" for help) [Ynaqdh]
```

ここで `Y` と答えると Rails プロジェクトがカレントディレクトリに作成される。
試しにサーバーを起動。

```
$ bundle exec rails server
```

すると以下のようなエラーが。

```
runtimes.rb:51:in `autodetect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
...
```

JavaScript の Runtime が必要なのでインストールする。

`Gemfile` の下記の行のコメントを解除する。

``` ruby:Gemfile(編集前)
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby
```

``` ruby:Gemfile(編集後)
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby
```

Bundler でインストールする。

```
$ bundle install --path vendor/bundle
```

もう一度サーバーを起動。

```
$ bundle exec rails server
=> Booting WEBrick
=> Rails 4.2.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2014-12-31 16:13:09] INFO  WEBrick 1.3.1
[2014-12-31 16:13:09] INFO  ruby 2.1.5 (2014-11-13) [x86_64-linux]
[2014-12-31 16:13:09] INFO  WEBrick::HTTPServer#start: pid=1524 port=3000
```

Rails のサーバーが立ち上がったのが確認できた。

# 接続トラブル
ローカル環境のブラウザから[http://localhost:3000/](http://localhost:3000/)にアクセスするも、繋がらない。
テストとして、awk でワンライナーサーバーを立てて実験。

以下のコマンドを実行し、ローカルマシンからブラウザ経由で[http://localhost:3000/](http://localhost:3000/)にアクセス。

```
$ awk 'BEGIN {port="3000";s="/inet/tcp/" port "/0/0";RS=ORS="\r\n";for(;;){if((s |& getline) > 0){printf "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\nPort 3000 test" |& s;}close(s);}}'
```

`Port 3000 test` が表示されたので、ローカルマシンと Vagrant 環境の通信は問題なし。
今回は Rails 側のトラブルの模様。

原因を探っていると、[Rails 4.2 のリリースノート](http://railsguides.jp/4_2_release_notes.html)にこんな記述が。

> 3.3 rails serverのデフォルトホスト
> Rackの変更 により、rails serverコマンドを実行した際のデフォルトのホストが0.0.0.0からlocalhostに変更されました。この変更は標準的なローカルでの開発ワークフローにほとんど影響を与えないはずです。http://127.0.0.1:3000 および http://localhost:3000 の動作はどちらも以前と同じであるからです。

> ただし、今回の変更により、別のPCからRailsサーバーへのアクセスは以前と同じようにはできなくなります。たとえば、development環境が仮想マシン上にあり、ホストマシンからこのdevelopment環境にアクセスする場合などがこれに該当します。 このような場合、サーバーを起動する際にrails server -b 0.0.0.0とすることで、以前と同じ動作を再現できます。

> 以前の動作に戻す場合は、必ずファイアウォールを適切に設定し、自社ネットワーク内の信頼できるPCだけが開発用サーバーにアクセスできるようにしてください。

`rails server`コマンドを実行する際にIPを指定してやれば良いっぽい。
オプションをつけてサーバーを再び起動。

```
$ bundle exec rails server -b 0.0.0.0
```

ローカルマシンからブラウザ経由で[http://localhost:3000/](http://localhost:3000/)にアクセスする。

![1a9d0352c5f7ac975328afc512aaa04d.png](https://qiita-image-store.s3.amazonaws.com/0/58390/50bd0f15-797f-d591-29a4-bde835968abf.png)

このような画面がブラウザに表示されればOK。

# さいごに
何も考えずに最新版の Rails 4.2 を突っ込んだせいで、
ローカルからの接続時に少々トラブルがあったが、
とりあえず Rails 周りの色々なテストを行える環境ができた。