Rails開発環境の構築（複数バージョン共存可能）（Homebrew編）

※お願い：最近時間がなかなか取れず、Rails5.xの時代になったというのに未だに5.xでの確認ができておりません。どなたか、5.xでも本記事の内容がうまくいった、と確認されました方はコメント欄にてご一報をいただけますと大変嬉しいです。

（本記事はRails 3.x〜4.x 対応です）

## はじめに：Railsをローカルインストールするという発想

[Macport版の記事](http://qiita.com/emadurandal/items/a60886152a4c99ce1017)が好評だったので、Homebrew版も投稿してみました。
Mac環境でrbenvを使って、Ruby・Rails環境を構築するための記事です。

bundlerでgemをRailsプロジェクト内にローカルインストールすることで、ruby環境を汚さずにRailsプロジェクトを生成できることを目的とします。
Rails自体もローカルインストールすることで、その都度好きなバージョンのRailsプロジェクトを生成し、共存させることができます（←ここ重要。古い書籍のRailsコードを試す時とか便利です）。

突っ込みどころがありましたら、遠慮なくコメントくださいませ。

## 前提環境

 * OSはMacを前提とする。（OSX Yosemiteで動作確認）
 * Railsのバージョンは3.x〜4.xを前提とする。
 * Rubyのビルドに必要なパッケージの導入にはHomebrewを使う（Gemに関してはもちろんBundler）。

Macを前提としているが、パッケージ管理ソフト以外の部分に関しては、Linux等でも使えるノウハウである。

## 本マニュアルが目指すこと

 * Ruby環境は、rbenvを使って、複数のバージョンを切り替えられるようにして導入する。
 * rbenv環境下のRuby環境に追加インストールするGemはbundlerのみ。
 * Railsもローカルにインストールすることで、Ruby環境を特定のバージョンのRailsで汚さずに、複数のバージョンのRailsプロジェクトを作成・共存できるようにする。
 * ほとんどのGemは、Railsプロジェクト内に閉じた形でインストール・管理する（つまり、Railsプロジェクトのvender/bundleディレクトリ内にGemをインストールする）

## rbenvとは

Ruby環境のバージョン切り替えツールである。Ruby（に限らないが）はバージョンの差違によって、ソフトウェアが正常に動いたり動かなかったり、といったことが往々にしてある。
そこで、特定のバージョンのRubyをドノーマルにインストールしてそれを使い続けるのではなく、バージョン切り替えツールでインストール・管理することで、使いたいソフトウェアや開発するプロジェクトに応じて複数のRuby環境を使い分けるのが最近のトレンドになっている。

Ruby環境のバージョン切り替えツールとしては、以前からRVMというものがあるが、以下のような欠点もあり、

* ヘビーウェイト・多機能。
* cdを独自のものに置き換えてしまう。
* Bundlerなどと相性が悪い。

ちょっと使うのに抵抗があるという人が多かったのも事実。そうした状況を受けて（？）、あのRuby on Railsで有名な37signalsが作った、より軽量な代替ツールがrbenvである。
以下のような特徴を持つ。

* 動作がRVMより速い。
* 既存コマンドを置き換えるような怖いことをしない。
* 環境変数によって自動的にRubyバージョンを切り替え可能。
* gemの管理はBundlerで行うことが前提。
* rubyをOSのシステム深部でなく、自分のホームディレクトリ以下（`.rbenv`ディレクトリ）にインストールできるので、OSの環境を汚さないという点でも安心感がある。

rbenvとRVMのより詳細な比較については、以下のサイト様のページをご覧ください。
「[rbenv と RVM との違い](http://passingloop.tumblr.com/post/10512902196/difference-between-rbenv-and-rvm)」（passingloop様のサイトより）

それぞれ設計思想が違うので、どちらを使うかは好みの問題でもあるが、しかし今後のトレンドとしてはRVMよりrbenvになりそうな感じなので、本記事ではrbenvを使う。

## rbenv、Rubyのインストール

rbenvとそのプラグインruby-buildをインストールする。
（ちなみにHomebrewを使ってもインストールできるようですが、常に最新版を使いたい人はgit cloneがいいような…？）

```console
$ git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
$ mkdir -p ~/.rbenv/plugins
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
```

rbenv用の以下の設定を `.bash_profile` に設定する。

```sh
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
```

書き換えた `.bash_profile` の設定を読み込む。

```console
$ source ~/.bash_profile
```

Homebrewをインストールする。インストールに関しては[こちらの_daisuke様の記事](http://qiita.com/_daisuke/items/d3b2477d15ed2611a058)を参考にしてください。ただし、最初のHomebrewのインストール元URLはたまに変わるので、必ず[公式サイト](http://brew.sh)で確認してください。


OpenSSLをインストールしないとrbenv環境での `bundle install` が失敗するらしいので、HomebrewでOpenSSLをインストールする。（参照：pygo様：http://d.hatena.ne.jp/CortYuming/20120618/p1 ）

```console
$ brew install openssl
```

readlineとiconvがないと動かないgemがあるらしいので、Homebrewでこの二つをインストール。
（参照：tech.portalshit.net様：http://tech.portalshit.net/2011/11/15/i-am-new-with-rbenv/ ）

```console
$ brew install readline
$ brew install libiconv
```

インストール可能なRubyのバージョンを調べる。

```console
$ rbenv install -l
```

Homebrew で インストールした openssl、readline、iconv のパスを教えて、rbenv でRubyをインストール。

```console
$ RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline) --with-openssl-dir=$(brew --prefix openssl) --with-iconv-dir=$(brew --prefix libiconv)" rbenv install 2.2.1 # ←バージョン番号は読み替えてね
$ rbenv rehash
```

以下のコマンドで、インストールしたRubyのバージョンのリストを確認できる

```console
$ rbenv versions
```

インストールしたRubyを有効にする

```console
$ rbenv global 2.2.1
```

## SSL証明書のインポート

ここまでの状態のRubyだと、SSL通信を行う処理をしようとした時に、

```
/Users/hoge/.rbenv/versions/2.0.0-p195/lib/ruby/2.0.0/net/http.rb:918:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (Twitter::Error::ClientError)
```

というエラーが起きます。そこで、対策として証明書をセットアップします。

まずは、証明書のパスを確認し、

```console
$ ruby -ropenssl -e "p OpenSSL::X509::DEFAULT_CERT_FILE"
```

返ってきたパスに対して、証明書をダウンロードします。

```console
$ sudo curl "https://curl.haxx.se/ca/cacert.pem" -o /usr/local/etc/openssl/cert.pem
```

（参考ページ:[rubyでSSL利用時に証明書エラーが発生する場合の対応](http://k-shogo.github.io/article/2013/08/22/ruby-ssl-connect-error/)）

これでOKです。

## Bundlerのインストール

Railsで利用するGemは各プロジェクト毎にbundlerで管理するようにしたいので

 * GEMでRuby環境にbundlerのみをインストール
 * bundlerを使って一時的にrailsをローカルにインストール
（Railsプロジェクトを作成するためだけに使用。railsすらローカルディレクトリにインストールする）
 * ローカルのrailsでプロジェクト(今回の例では”example”)を作成
 * railsをローカルインストールするために使ったbundlerの環境を削除
 * exampleプロジェクト内で必要なgemをbundlerでローカルインストール

という手順を踏む。でははじめよう。


GEMでRuby環境にbundlerのみをインストールする。

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

ちなみに現在有効なrubyにインストールされたgemの確認は以下のコマンドで行う。

```console
$ rbenv exec gem list
```

インストールしたgemパッケージの保存場所を調べるには以下のコマンドを使う。

```console
$ rbenv exec gem which bundler
```


## RailsのローカルインストールとRailsプロジェクトの作成

**（新規Railsプロジェクトを作る時は、常にこのステップから行う）**

bundlerを使って一時的にrailsをローカルにインストール。（Railsプロジェクトを作成するためだけに使用。railsすらローカルディレクトリにインストールする）
まず、Railsプロジェクトを作りたいディレクトリに移動して、そこで `Gemfile` を作る。

```console
$ cat << EOS > Gemfile
source "http://rubygems.org"
gem "rails", "4.1.1" # ←ローカルインストールしたいRailsのバージョンを指定。指定しなければ最新版が入る。
EOS
```

railsを `vender/bundle` ディレクトリ以下にインストールする。

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

（このように、 `bundle install` する際に `--path vendor/bundle` をつけることで、gemのインストール先がRuby環境でなく、 ローカルの`vendor/bundle` ディレクトリ以下になる）

インストールしたgemを確認したい場合は、以下を実行。

```console
$ bundle list
```

railsでプロジェクト(今回の例では”example”)を作成。

```console
$ bundle exec rails new example --skip-bundle
```

（ `vendor/bundle` に入ったgemを使ってコマンドを実行したい場合は上記のように `bundle exec 〜` のようにする）
（ `--skip-bundle` の指定を忘れないように！そうでないと `bundle install` が発動し、Ruby環境にgemがインストールされてしまう！）

railsをローカルインストールするために使ったbundlerの環境と、ローカルのrailsを削除する。

```console
$ rm -f Gemfile
$ rm -f Gemfile.lock
$ rm -rf .bundle
$ rm -rf vendor/bundle
```

## Railsプロジェクトの環境セットアップ

必要に応じて、example内のGemfileの内容を編集する（Rspecとか、Guardとか、色々入れるよね）。

次に、example内に移動し、Gemfileに書かれたGemのインストールを行う。
この際も `--path vendor/bundle` オプションをつけて `bundle install` することでプロジェクト内に閉じた状態でGemをインストールすることができる。

```console
$ cd example
$ bundle install --path vendor/bundle
```

(この `bundle install --path vendor/bundle` で、再びrails(及び関連Gem)が今度はRailsプロジェクトの `vender/bundle` ディレクトリ以下にインストールされる)

以下の２つの理由から、Gitの管理対象から `vendor/bundle` ディレクトリを外す。
* `vendor/bundle`ディレクトリにあるGemsは容量を食うのでGitリポジトリに入れたくない。
* GemfileやGemfile.lockファイルはGitの管理対象なので、cloneした人はそれをもとに`bundle install --path vendor/bundle`すれば、簡単に同じGem環境を導入できる。

```console
$ echo '/vendor/bundle' >> .gitignore
```

## Railsプロジェクトの起動

以下のようにして、Railsの起動に成功したら、この記事の目的は達成された。おめでとう！

```console
$ bundle exec rails server
```

# 以下、Tips

## gemのインストール先の判断（Ruby環境下 or bundlerでのローカルインストール）について

基本的には、そのプロジェクトでのみ使いたいgemであれば、bundlerで`bundle install --path vendor/bundle`して、プロジェクトに閉じた形でgemをローカルインストールし、`bundle exec ~ `で実行する形を取るのがよい。
ただし、`bundler`や`pry`など、

* どのプロジェクトでも共通して使いたい。
* 複数のバージョンを使い分ける必要性が基本的になく、常に最新バージョンであればよい。

という性質のgemであれば、bundlerでローカルインストールするのでなく、`rbenv exec gem install ~ `としてRuby環境に直接インストールしてしまった方が利便性が高い。
gemの特性と自分の利用シーンに合わせて、gemのインストール場所は使い分けよう。

## 間違えてRuby環境の方にいろんなGemが入ってしまった場合の対処

以下で全てのgemをアンインストールする。その後、標準でインストールされていたgemやbundlerを入れ直すこと。

```console
$ rbenv exec gem list | awk '{print "rbenv exec gem uninstall " $1}' | sh -xv
```

あるいは、以下の方法でRuby環境ごと削除して、rubyを導入しなおしても良い。

## 不要になったバージョンのRuby環境を削除する

```console
$ rbenv uninstall -f 2.0.0-p195
$ rbenv rehash
```

## rbenvを最新版に更新する
rbenvのインストール方法によるが、今回はgit cloneでインストールしたため、普通にgit pullすればよい。

```console
$ cd ~/.rbenv/
$ git pull
$ cd ~/.rbenv/plugins/ruby-build/
$ git pull
```

## rbenvで、1.9.3-p125より古いrubyをビルド・インストールする

1.9.3-p125 より前のバージョンのrubyはllvm-gccではなくGCCでコンパイルされていたようです。よって、Xcode4.2以降がインストールされている場合、GCCがないので（/usr/bin/gccはllvm-gccへのシンボリックリンクとなっている）、ビルドに失敗します。

以下のような感じで失敗します。

```console
$CONFIGURE_OPTS="--with-openssl-dir=/opt/local --with-readline-dir=/opt/local --with-iconv-dir=/opt/local" rbenv install 1.8.7-p370

ERROR: This package must be compiled with GCC, but ruby-build couldn't
find a suitable `gcc` executable on your system. Please install GCC
and try again.

DETAILS: Apple no longer includes the official GCC compiler with Xcode
as of version 4.2. Instead, the `gcc` executable is a symlink to
`llvm-gcc`, a modified version of GCC which outputs LLVM bytecode.
For most programs the `llvm-gcc` compiler works fine. However,
versions of Ruby older than 1.9.3-p125 are incompatible with
`llvm-gcc`. To build older versions of Ruby you must have the official
GCC compiler installed on your system.

TO FIX THE PROBLEM: Install the official GCC compiler using these
packages: https://github.com/kennethreitz/osx-gcc-installer/downloads
You will need to install the official GCC compiler to build older
versions of Ruby even if you have installed Apple's Command Line Tools
for Xcode package. The Command Line Tools for Xcode package only
includes `llvm-gcc`.

BUILD FAILED
```

この対策としては、Homebrewでapple-gcc42をインストールすることです。[参考URL](http://codenote.net/mac/homebrew/751.html)

```console
$ brew install https://raw.github.com/Homebrew/homebrew-dupes/master/apple-gcc42.rb
```

さらに、ビルドにautoconfが必要なので、それもインストールします。

```console
$ brew install autoconf
```

そうして、rubyをもう一度ビルドしてみましょう。これでビルドが通る……かとおもいきや、Yosemiteだとビルドがこけます。
某所で調べたところ（URL忘れた）、2015/04/5現在では残念ながら普通のやり方ではビルドを通すことができないようです…。誰かがソリューションを用意してくれるといいですね（他力）

# 謝辞

以下のサイト様の情報をかなり使わせていただきました。ていうかかなりの部分をコp（ry

 * [吾輩のメモである](http://d.hatena.ne.jp/clmind/20111109/1320814435)（clmind様）

以下のサイト様からも情報をいただきました。

 * [pygo](http://d.hatena.ne.jp/CortYuming/20120618/p1)（CortYuming様）
 * [tech.portalshit.net](http://tech.portalshit.net/2011/11/15/i-am-new-with-rbenv/)様
 * [_daisuke](http://qiita.com/_daisuke/items/d3b2477d15ed2611a058)様
 * [passingloop](http://passingloop.tumblr.com/post/10512902196/difference-between-rbenv-and-rvm)様
 * [Dev.Wan.Co](http://k-shogo.github.io/article/2013/08/22/ruby-ssl-connect-error/)様
 * [codenote.net](http://codenote.net/mac/homebrew/751.html)様