Ubuntu 16.04 (Xenial) でRoRをはじめる

はじめまして！

[Ruby技術者認定試験](http://www.ruby.or.jp/ja/certification/examination/) Gold持ちのRuby歴15年の上級初心者です。

今日はRoRの開発環境セットアップにチャレンジしたいと思います！！

## 前提条件

* Ubuntu 16.04 LTS (Xenial) x86_64

## 全体方針

1. かんたんインストール。
   * [rbenv](https://github.com/rbenv/rbenv) 使う。
2. システムをなるべく汚染しない。グローバルにインストールされたGemとか許さない。

（手順はDockerで検証環境 `ubuntu:16.04` 立てて検証しています。）

## aptでパッケージインストール

まずはrootユーザとして必要なものをインストールします。行儀のいい人はちゃんと `sudo` してね！

```console:console
# rbenv: Rubyのインストレーションを選ぶことができるツール。
# ruby-build: rbenv install コマンドを追加できるツール。これがないと好きなバージョンのRuby入れられないよ！
# ruby-dev: なんか後々の拡張(Gem)のインストールで必要。
%> apt update ; apt install -y rbenv ruby-build ruby-dev
```

大変ありがたいことに、この時点で `ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]` が入ってしまっているのですが、無視してrbenvでセットアップしていきます。

## rbenvの初期化

ここからは一般ユーザとして必要なものをインストールしていきます。

まずはrbenvを有効化するように `~/.profile` に `eval "$(rbenv init -)"` を追記します。

```console:console
# ~/.bashrc とか別のやつでもいいです。
$> echo 'eval $(rbenv init -) >> ~/.profile'
```

いったんログインしなおすか、リロードしましょう。

```console:console
# リロードする場合：リロード＆コマンドのハッシュ初期化
$> . ~/.profile
$> hash -r
```

成功していれば下記のように `~/.rbenv/shims` が `${PATH}` に追加されているはずです。

```console:console
$> echo "${PATH}"
/home/user01/.rbenv/shims:/home/user01/bin:/home/user01/.local/bin:/home/user01/bin:/home/user01/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
```

`~/.rbenv/shims` の中にはRubyのコマンドを偽装するbashコマンドが入っており、そこにパスが通るわけですね。

### rbenvでRubyインストール

#### どんなRubyがあるの？

まずはどんなバージョンがあるか見てみよう。 :eyes: 

```console:console
$> rbenv install --list
Available versions:
  1.8.6-p383
  1.8.6-p420
  1.8.7-p249
  :
  : (jruby-9.0.3.0 とか mruby とか)
  :
  rbx-2.5.7
  rbx-2.5.8
  ree-1.8.7-2011.03
  ree-1.8.7-2011.12
  ree-1.8.7-2012.01
  ree-1.8.7-2012.02
  topaz-dev
```

以下の種類のバージョン違いが存在しているようです。

* 無印
* maglev-*
   * http://maglev.github.io/
* mruby-*
   * https://mruby.org/ 組み込み用Ruby。
* jruby-*
   * http://jruby.org/ JVMで動くRuby。
* rbx-*
   * https://rvm.io/interpreters/rbx Rubinius とかいうC++/LLVMで書かれたRuby。
* ree-*
   * http://www.rubyenterpriseedition.com/ Ruby Enterprise Edition とかいうやつ。
* topaz-dev
   * https://github.com/topazproject/topaz Pythonで書かれたRuby。

### インストール

いろいろRubyの種類がありますが、無難に無印の最新（？）を選んでおきましょう。

```console:console
$> rbenv install 2.2.3
Downloading ruby-2.2.3.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/df795f2f99860745a416092a4004b016ccf77e8b82dec956b120f18bdc71edce
Installing ruby-2.2.3...
Installed ruby-2.2.3 to /home/user01/.rbenv/versions/2.2.3
```

やたら時間かかりました。

### 構成のアクティベートと確認

入れたRubyの構成(`2.2.3`)を有効化します。

```console:console
$> rbenv global 2.2.3
```

確認してみましょう。

```console:console
$> rbenv version
2.2.3 (set by /home/user01/.rbenv/version)

$> ruby --version
ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]

$> gem --version
2.4.5.1
```

これでOKです。

### gem構成の確認

ここまでちゃんとやっていれば、ユーザの領域しか侵さないgemの構成ができているはず。

```console:console
$> gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 2.4.5.1
  - RUBY VERSION: 2.2.3 (2015-08-18 patchlevel 173) [x86_64-linux]
  - INSTALLATION DIRECTORY: /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0
  - RUBY EXECUTABLE: /home/user01/.rbenv/versions/2.2.3/bin/ruby
  - EXECUTABLE DIRECTORY: /home/user01/.rbenv/versions/2.2.3/bin
  - SPEC CACHE DIRECTORY: /home/user01/.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /home/user01/.rbenv/versions/2.2.3/etc
  - RUBYGEMS PLATFORMS:
    - ruby
    - x86_64-linux
  - GEM PATHS:
     - /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0
     - /home/user01/.gem/ruby/2.2.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => false
     - :bulk_threshold => 1000
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /home/user01/.rbenv/versions/2.2.3/bin
     - /usr/lib/rbenv/libexec
     - /home/user01/.rbenv/shims
     - /home/user01/bin
     - /home/user01/.local/bin
     - /usr/local/bin
     - /usr/bin
     - /bin
     - /usr/local/games
     - /usr/games
```

`INSTALLATION DIRECTORY` あたりに `/var/gem/libs ...` っぽく設定されてしまっている人は `rbenv global 2.2.3` を忘れているかもしれません。


## Bundler を入れよう

### Bundler って何？

http://bundler.io/

> Bundler provides a consistent environment for Ruby projects by tracking and installing the exact gems and versions that are needed.

JavaでいうMaven、プロジェクト内Gemの依存性管理ツールということですね。

Gemを管理するツールではありますが、Bundler自体はGemでインストールされます。


### Bundler のインストール

では、下記コマンドで Bundler (○ bundle*r* ✘ bundle) を入れましょう。

```console:console
$> gem install bundler --no-document
gem install bundler
Successfully installed bundler-1.12.5
1 gem installed
```

`--no-document` をつけないとRDocドキュメントというものが生成されてしまって遅いらしいです。そもそも基本的にgemのインストール時、ドキュメントは必要ないらしいので、できるだけつけたほうがいいらしいです。

でも毎度つけるのは面倒なので、 `~/.gemrc` に `gem: --no-document` を追記すれば勝手に追加してくれるようです。 (http://stackoverflow.com/questions/1381725/how-to-make-no-ri-no-rdoc-the-default-for-gem-install/17201281)

```
$> echo 'gem: --no-document' >> ~/.gemrc
```

## Bundler でRailsを入れよう

### Gemfile

適当にプロジェクト用ディレクトリを作ってRailsを入れていきます。

```console:console
$> mkdir ~/rails-test
$> cd ~/rails-test
$> bundle init
Writing new Gemfile to /home/user01/rails-test/Gemfile
```

Gemfile とかいうのができました。中身はこんな感じ。(抜粋)

```rb:Gemfile
source "https://rubygems.org"
```

[プロジェクトで必要なライブラリがあれば](https://rubygems.org/)、ここに追記していけばいいわけですね。

今回は [rails](https://rubygems.org/gems/rails) が必要なので、ここに追記します。

```rb:Gemfile
source "https://rubygems.org"
gem 'rails', '~> 5.0'
```

### GemfileからRailsインストールの実行

デフォルトの `bundler install` であれば、ユーザのディレクトリ
（`/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/` など） にGemがインストールされますが、ここではプロジェクト依存のGemのインストール先をプロジェクト内のディレクトリ（ `vendor/bundle` ）にしたいと思います。

下記のコマンドでインストール可能です。

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

# bundler というコマンドもありますが、 bundle と同じようです。でもbundleコマンドのほうがメジャーのようです。
```

なお、[次回以降 `--path` オプションはつける必要はありません。](http://bundler.io/v1.12/bundle_install.html#REMEMBERED-OPTIONS) `.bundle/config` ファイルに記憶されます。

```:.bundle/config
---
BUNDLE_PATH: vendor/bundle
BUNDLE_DISABLE_SHARED_GEMS: true
```

### Rails初期化

いよいよrailsの初期化。初期化中、Gemfileがコンフリクトするので、サブディレクトリ `rails-app` にセットアップします。

```console:console
$> bundle exec rails new --skip-bundle rails-app
```

そのまま実行するとrailsのbundleインストールを望まない形で実施する（＝ `vendor/bundle` 以外にインストールすｙる）ので、 `--skip-bundle` をつけていますが、別につけなくても構いません。

あらためてRailsの中身をインストールしてあげましょう。

```console:console
$> cd rails-app
$> bundle install --path vendor/bundle
```

### Rails起動

では立ち上げてみましょう。

```console:console
$> bundle exec rails server
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:89:in `rescue in block (2 levels) in require': There was an error while trying to load the gem 'uglifier'. (Bundler::GemRequireError)
Gem Load Error is: Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.
Backtrace for gem load error is:
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/execjs-2.7.0/lib/execjs/runtimes.rb:58:in `autodetect'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/execjs-2.7.0/lib/execjs.rb:5:in `<module:ExecJS>'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/execjs-2.7.0/lib/execjs.rb:4:in `<top (required)>'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/uglifier-3.0.0/lib/uglifier.rb:5:in `require'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/uglifier-3.0.0/lib/uglifier.rb:5:in `<top (required)>'
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:86:in `require'
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:86:in `block (2 levels) in require'
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:81:in `each'
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:81:in `block in require'
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:70:in `each'
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:70:in `require'
/home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler.rb:102:in `require'
/home/user01/rails-test/rails-app/config/application.rb:7:in `<top (required)>'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:88:in `require'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:88:in `block in server'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:85:in `tap'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:85:in `server'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
/home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands.rb:18:in `<top (required)>'
bin/rails:4:in `require'
bin/rails:4:in `<main>'
Bundler Error Backtrace:
        from /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:85:in `block (2 levels) in require'
        from /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:81:in `each'
        from /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:81:in `block in require'
        from /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:70:in `each'
        from /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler/runtime.rb:70:in `require'
        from /home/user01/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/lib/bundler.rb:102:in `require'
        from /home/user01/rails-test/rails-app/config/application.rb:7:in `<top (required)>'
        from /home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:88:in `require'
        from /home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:88:in `block in server'
        from /home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:85:in `tap'
        from /home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:85:in `server'
        from /home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
        from /home/user01/rails-test/rails-app/vendor/bundle/ruby/2.2.0/gems/railties-5.0.0/lib/rails/commands.rb:18:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'
```

立ち上がらん！ http://qiita.com/pugiemonn/items/11a2bc8403e5947a8f13 によると、Gemfile内の `therubyracer` というやつを有効にしてから、

```rb:Gemfile
# コメントはずす
gem 'therubyracer', platforms: :ruby
```

`bundle install` するとうまくいくようです。

```console:console
$> bundle install
```

では再び起動！

```console:console
$> bundle exec rails server                                                                                                                                                                          
=> Booting Puma
=> Rails 5.0.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.6.0 (ruby 2.2.3-p173), codename: Sleepy Sunday Serenity
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
```

http://localhost:3000 に起動しているはずです。

## 感想

* 素直にやらなかったせいか、全般的に面倒だった。
* ちょいちょいパッケージを入れなきゃいけないあたりが、Java系とくらべて面倒。