Rubyはじめて学習メモ 「開発環境構築からRails Bootstrap3組み込みまで」

土日でRubyを学習しようと思い、macにRuby開発環境構築してRSpec試したあと、Rails入れてローカルでWebサーバを立ち上げました。最後にRailsにBootstarp3を組み込んでます。学習メモ。ツッコミ歓迎

# 1.構成概要
Mac OSX El Capitan‎ + Homebrew + git + rbenv + ruby,ruby-build,rails,bundler,bootstrap-sass

# 2.macにruby環境構築するまで

macで開発する場合、xcodeが必要。AppStoreでダウンロードしておく（大変時間が掛かる）
その後macのパッケージ管理ソフトHomebrewをインストール。rbenvはmacで複数versionのRubyを扱えるようになるコマンドです。便利。

<img width="227" alt="スクリーンショット 2016-07-02 12.53.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/98508d1c-d72d-b20a-f970-66fba9fd6215.png">



```shell-session:
# brewインストールして最新化する
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
sudo xcodebuild -license  # xcodeのライセンスを承諾する
echo 'export PATH=/usr/local/bin:$PATH' >> .bash_profile
source .bash_profile
brew doctor
brew update

# gitとrbenvをインストール
brew install git
brew install readline
brew install openssl
brew install ruby-build
brew install rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> .bash_profile
echo 'eval "$(rbenv init -)"' >> .bash_profile
source .bash_profile

```

参考にした記事：http://qiita.com/keneo/items/1772adc2ebbde229fb71

# 3.rbenvで最新の安定版Rubyをインストールする。
Rubyには安定板と開発版という概念があるみたいです。
手元の本には偶数と奇数で安定版と、開発版を区別するといった記述があったのですがver1.9以降は異なる模様です。さらに調べてみるとRuby公式に現在の安定版は **2.3.1** と掲載されていたので、2.3.1が安定版だと判りました。（実際は2.2.5を利用しました）
https://www.ruby-lang.org/ja/downloads/

<img width="636" alt="スクリーンショット 2016-07-02 13.05.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/d89c0a29-d944-f3a8-4e46-ca3f618141af.png">


```shell-session:
# インストール可能なRuby version 一覧表示
rbenv install -l

# 2.3.1をインストール
rbenv install 2.3.1

# rbenvで切り替え可能なRuby versionを表示
rbenv versions

# defaultのRuby versionを切り替える
rbenv global 2.3.1

# rubyのversion確認(2.3.1となっていること)
ruby -v

```

# 4.RailsインストールとWebサーバ起動まで

```shell-session

# railsのインストール
gem install rails
gem install bundler

# 反映
rbenv rehash
source ~/.bash_profile

# version確認（Rails 5.0.0と表示された）
rails -v

# Railsプロジェクトを構築する
rails new rails_study

# RailsのDBモデル構築
cd ./rails_study
rails generate scaffold user name:string age:integer

# DB migrate
rake db:migrate

```

### 4-1.rails new とは？
railsで開発する上での雛形を作成してくれる便利コマンド。ログを見るとMVCモデルで開発するためのcontrollerから始まって、HTML用のtemplateファイルまで生成された。cssはsassで、jsはcoffie_scriptで書くことを推奨しているみたいだ。test用のfixtureデータまで生成されてしまった。

### 4-2.rails generate scaffoldとは
scaffold（スキャフォールド）はモデルを自動生成する便利コマンド。日本語だと骨格。

### 4-3.rake db:migrate 
rakeコマンドは、rubyで処理を記述できるビルドコマンド
rake db:migrate でDBマイグレーションを実行した。
- [マイグレーションの実行(rake db:migrate)](http://railsdoc.com/rake)

optionには環境指定が可能なようなので、上手く設定すればproductionだけ垂直分割したDBに適切にテーブル作成とかできるのだろうか?当然のようにrollbackに対応している。他社事例調べてみたら、色々出てきた。垂直分割や水平分割などを考慮したDBschema運用については各社独自ノウハウがありそう。

- [クックパッドにおける最近のActiveRecord運用事情](http://techlife.cookpad.com/entry/2014/08/28/194147)

### 4-4.DBはどこへ？
mysqlの設定しなくても、db:migrate出来てしまった。生成されたRailsのソースをgrepしたらDBにsqlite3が設定されていた

```yaml:config/database.yamlより
default: &default
  adapter: sqlite3
  pool: 5
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3
```

# 5.RailsのWebServer起動して疎通確認

```shell-session
# 起動
>>> rails server
=> Booting Puma
=> Rails 5.0.0 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
```

あとはブラウザを開いてhttp://localhost:3000 にアクセスするとwelcomeページが表示された
<img width="566" alt="スクリーンショット 2016-07-02 13.53.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/f4d2edbb-b7d1-aea0-8278-f8e588040e07.png">



# 6.開発環境IntelliJ IDEAをインストールする
ここまで一切Rubyのコード書いてません。Rubyを本格的に書くためにIDEを設定します。Pythonの書き方はPyCharm先生に教わりました。Rubyの書き方はIntelliJ IDEA先生に教えてもらおうと思います。

良いIDEを利用すると、言語の正しい書き方と初心者にありがちなミスが減って学習効率が高まるんじゃないかなー

<img width="533" alt="スクリーンショット 2016-07-02 14.13.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/36aae412-5c36-6534-a3b9-a10f24b0d160.png">

JavaIDEとか書いてあるけど、plugin入れたらPythonもErlang/OTPも、頑張ればC#だってIntelliJ IDEAでかけます。（C#はVisualStudio利用した方がよい）
https://www.jetbrains.com/idea/

## 6-1.colorを最適化する
文字色はcolor-themesにユーザ作成済みの配色が多数掲載してあるので、好きな配色をダウンロードして設定する。設定はFile >> import settings

http://color-themes.com/?view=index
<img width="1180" alt="スクリーンショット 2016-07-02 14.17.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/1a5aa0ae-3199-dfc6-9a36-ba9e0509a950.png">


## 6-2.Rubyプラグインを設定する
IntelliJ IDEA >> Preference

<img width="627" alt="スクリーンショット 2016-07-02 14.30.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/da600d25-61f8-fe8c-33da-553282b27c8f.png">



## 6-3.ProjectSettingsを設定してコードジャンプを有効にする

File >> Project Structureを開いて設定していきます。

### 6-3-1.SDKにRubyを設定する
<img width="726" alt="スクリーンショット 2016-07-02 14.20.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/fe6473ea-9f5d-8af5-7091-a45fb3dc9fdd.png">



### 6-3-2.classpathにgemを設定する
インストールしたgemがIDE内で適切にimportされない問題を解消するためにClassPathにを設定する

```rb
# rubyのgem
~/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/

# bundler
~/.rbenv/versions/2.2.5/lib/ruby/gems/2.2.0/gems/bundler-1.12.5/

# ProjectPath
~/ruby/ruby_study/
```

<img width="886" alt="moza.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/971c8b38-4811-15c8-0ec9-a06f5f71b2d5.png">



## 6-4.RailsのコードをIntelliJ IDEAから読む
正しく設定してあるなら、コードジャンプが完全につながるため、Railsのコードを追うことができるようになっているはずです( ・ㅂ・)و ̑̑ 


■ 1. 生成したControllerの継承基classを追いかける
<img width="365" alt="スクリーンショット 2016-07-03 12.34.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/b3efa49d-7229-8747-bfa4-d51eefc35cfc.png">

■ 2. command + clickでコードジャンプ
<img width="835" alt="スクリーンショット 2016-07-03 12.37.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/8bc46282-af2a-eafb-7e48-bb23e97eb2b4.png">

■ 3. Railsライブラリ内のコードが読めた
<img width="617" alt="スクリーンショット 2016-07-03 12.35.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/e92a4d24-5d10-3f7b-7284-9c833f5eeb16.png">


# 7.ほぼ初めてのRuby
いよいよコード書いてみます。まずはパスを通すおまじないから

```shell-session
# プロジェクトのディレクトリ作成
mkdir -p ~/ruby/ruby_study

# rubyのPATHを確認
ruby -e 'puts $LOAD_PATH'

# プロジェクトのディレクトリを登録
export RUBYLIB=~/ruby/ruby_study

# プロジェクトのPATHが登録されていることを確認
ruby -e 'puts $LOAD_PATH'
```


### 7-1.足し算の関数とテストコードを書いた
開発する内容は、足し算の関数とテストコードです。

```rb:extend_number.rb
def extend_number(a, b)
  a + b
end

p extend_number(1, 2)
```

```shell-session:実行結果
$ ruby ./extend_number.rb
3
```

return要らないのが気持ち悪いけど完成！

### 7-2.RSpecで関数のテストを書く

RSpecをインストールして、テストコードを書いていきます。テストは{FileName}_spec.rb という名前にするお約束があるみたいです。

```shell-session:実行結果
# rspecのインストール
gem install rspec

# テスト作成
touch extend_number_rspec.rb

# テスト実行
rspec ./

```

テストを書いていきます。正常系と異常系を書き分けてみた。

```extend_number_rspec.rb
require 'spec_study/spec/spec_helper'
require 'spec_study/extend_number'

describe 'add' do
  it 'extend正常系' do
    expect(extend_number(1,2)).to eq 3
    expect(extend_number(5,5)).to eq 10
    expect(extend_number(-5,5)).to eq 0
  end
  it 'extend異常系' do
    expect(extend_number(1,1)).not_to eq 1
    expect(extend_number(5,5)).not_to eq 1
  end
end
```

```shell-session:テスト実行結果
$ rspec ./
..

Finished in 0.00068 seconds (files took 0.07552 seconds to load)
2 examples, 0 failures

```

# 8. RailsでURL追加
次はRailsのプロジェクトでURLを追加してWebページを実装しようと試みました。最初は勉強のために **rails generate** コマンドを使わずに手で全部書きたかったのですが、Web上にあまり資料がない。そもそも標準的な開発方法だとModelもcontroller追加もコマンドから実施するのだろうか？ と道に迷って手が止まったのでAmazonで評判が良かった本を近所の本屋で買ってきました。

<img width="274" alt="スクリーンショット 2016-07-03 12.48.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/5c116d91-c21c-ea90-df43-767bbc8b9a8b.png">

パラパラ読むとコマンドで生成するのが正しいみたいなので実行してみました

```shell-session:controllerの追加
$ rails g controller tea
Running via Spring preloader in process 1471
      create  app/controllers/tea_controller.rb
      invoke  erb
      create    app/views/tea
      invoke  test_unit
      create    test/controllers/tea_controller_test.rb
      invoke  helper
      create    app/helpers/tea_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/tea.coffee
      invoke    scss
      create      app/assets/stylesheets/tea.scss

# コントローラの削除コマンド
# rails g controller tea
```

色々生成されてしまったので調べてみました。html,js,cssまで生成されてしまうんですね。


```shell-session:生成されたファイル
# controller
app/controllers/tea_controller.rb

# js と css
app/assets/javascripts/tea.coffee
app/assets/stylesheets/tea.scss

# テスト用
app/helpers/tea_helper.rb
test/controllers/tea_controller_test.rb
```

## 8-1. テスト実行と、あえてテストを失敗させてみる

```shell-session:テスト実行
$ rake test
Finished in 0.681177s, 10.2763 runs/s, 13.2124 assertions/s.
```

テスト失敗させるコードを書く

```rb:tea_controller_test.rb
require 'test_helper'

class TeaControllerTest < ActionDispatch::IntegrationTest
  test "the truth" do
    assert true
    assert nil  # エラー
  end
end

```


```shell-session:テスト実行、無事エラーが出た
$ rake test
F

Failure:
TeaControllerTest#test_the_truth [/work/ruby_study/rails/sample/test/controllers/tea_controller_test.rb:6]:
Expected nil to be truthy.


bin/rails test test/controllers/tea_controller_test.rb:4
```

無事エラーが出たことで、自動生成されたテストコードがちゃんと試験されていることが判りました。

## 8-2.ルーティング定義してRailsでHelloWorld
生成したcontrollerで **render text** を定義して、**/config/routes.rb** にルーティングを定義してやれば新規発行したURLでHelloWorldができる模様です。routes.rbの定義方法は[公式ドキュメントのここ見ろ](http://guides.rubyonrails.org/routing.html)ってコード内に書いてありました。親切！


```rb:app/controllers/tea_controller.rb
class TeaController < ApplicationController
  def index
    render text: 'Hello World hogehoge!'
  end
end
```

```rb:config/routes.rb
Rails.application.routes.draw do
  resources :users

  # tea
  get '/tea/index', to: 'tea#index'
end
```

あとは ** rake test ** でテストが通ることを確認したあと、 **rails server** でWebサーバ起動して指定したURLにブラウザからアクセスしてみます。

http://localhost:3000/tea/index

<img width="212" alt="スクリーンショット 2016-07-03 13.41.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/ef20e726-c448-ce6c-1dad-4d1527f49db9.png">

## 8-3.GET
HTTP GETでtea_idを指定して、適切に表示文字を切り替えてみます。

```rb:app/controllers/tea_controller.rb
class TeaController < ApplicationController
  def index
    render text: 'Hello World hogehoge!'
  end

  def get
    tea_list = {
        1=>'orange tea',
        2=>'apple tea',
        3=>'japanese tea',
    }
    tea_id = params['id'].to_i
    tea_name = tea_list[tea_id]
    render text: sprintf('id:%{number} is %{tea_name}',
                         :number=>tea_id.to_s,
                         :tea_name=>tea_name)
  end
end

```

http://localhost:3000/tea/get/2 へブラウザへアクセスした結果
<img width="167" alt="スクリーンショット 2016-07-03 15.52.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/a678248a-ba32-862f-5746-7c179d3a9078.png">


## 8-4.テンプレート導入する
文字列を直接表示するのは、ちょっとアレなので、現代風にテンプレートを新規作成してみました。


```erb:/app/views/tea/get.erb
<h1>Tea Get</h1>
<%= @tea_name %>[<%= @tea_id %>]
```

```rb:app/controllers/tea_controller.rb
class TeaController < ApplicationController
  def index
    render text: 'Hello World hogehoge!'
  end

  def get
    tea_list = {
        1=>'orange tea',
        2=>'apple tea',
        3=>'japanese tea',
    }
    tea_id = params['id'].to_i
    @tea_id = tea_id
    @tea_name = tea_list[tea_id]
  end
end

```

■ ブラウザで閲覧
<img width="218" alt="スクリーンショット 2016-07-03 16.18.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/23f5d1d9-bf48-02c4-7c61-bd2b59fa0e68.png">


### 8-4-1.IntelliJ IDEAにRails用設定を入れる
テンプレート内での補完が効かなかったので、設定を入れました。Rails用の設定詳細は[IntelliJ公式ドキュメントに詳しく書いてありました](https://confluence.jetbrains.com/display/RUBYDEV/Opening+Rails+projects+in+IntelliJ+IDEA)

■ 設定したら補完されるようになった（配色なんとかしたい）
<img width="907" alt="スクリーンショット 2016-07-03 16.14.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/572b469e-4f59-ea07-6b83-bddde5401169.png">


# 9.paramsはどこからきたのか？
HTTP GETのviewを実装したときに、疑問に思ったのですがHTTP GETパラメーターのparamsはどこからやってきたのでしょうか？ ソースコードを追っていくと[ActionController](https://github.com/rails-api/rails-api/blob/master/lib/rails-api/action_controller/api.rb#L5) に到着しました。読みきれなかったのでstack overflowから回答もってきた　[Rails: Where “params” is defined?](http://stackoverflow.com/questions/4456070/rails-where-params-is-defined)

```If you look at the Rails API at http://api.rubyonrails.org/, you will find params is just a function that returns the paramaters of the request object.```

requestの関数だよ！ってことみたい。[action_controller/metal.rbに定義されてました。](https://github.com/rails/rails/blob/844fb632d4b6744172cfcc87d4143efbf451d679/actionpack/lib/action_controller/metal.rb#L159)　しかしなんでMetalなんて名前にしたんだろう。Ruby - Metalということ？


# 10.インスタンス変数が判らない
Railsのコードを読んでいて、理解できなかったのが *@で始まる変数* これはインスタンス変数と呼ぶらしいです。手元の本を紐とくと、Rubyには変数が4種類あるそうです。


```rb:Rubyには変数が4種類ある
# ローカル変数とグローバル変数では、スコープが異なる
# ローカル変数
f = 1

# グローバル変数
$f = 1

# インスタンス変数
@f = 1

# クラス変数
@@f = 1
```

## 10-1. インスタンス変数
インスタンス変数はインスタンス毎に異なった範囲を管理できる（インスタンス単位のスコープ）。コード書いたらインスタンス変数の概念が腑に落ちた。

```rb:インスタンス変数
class Dog
  def initialize(name)
    @dog_name = name
  end
  def bow()
    sprintf('%{dog_name}< bowbow', dog_name:@dog_name)
  end
end

p Dog.new('pochi').bow
p Dog.new('kuro').bow

```

```shell-session:実行結果
$ ruby dog.rb 
"pochi< bowbow"
"kuro< bowbow"
```

## 10-2. クラス変数
クラス変数はclass毎に値を管理する（スコープはclass単位）

```rb:犬が鳴きすぎるとオーナが叱る
class Dog
  @@count = 0

  def initialize(name)
    @dog_name = name
  end

  def bow
    # 犬が5回以上鳴いたらオーナーが鳴く
    @@count += 1

    if @@count > 5
      "owner< shut up!!"
    else
      sprintf('%{dog_name}< bowbow', dog_name:@dog_name)
    end
  end
end

p Dog.new('pochi').bow
p Dog.new('kuro').bow
p Dog.new('shiro').bow
p Dog.new('pochi').bow
p Dog.new('kuro').bow
p Dog.new('shiro').bow
p Dog.new('pochi').bow
p Dog.new('kuro').bow
p Dog.new('shiro').bow
```

```shell-session:実行結果
$ ruby dog.rb 
"pochi< bowbow"
"kuro< bowbow"
"shiro< bowbow"
"pochi< bowbow"
"kuro< bowbow"
"owner< shut up!!"
"owner< shut up!!"
"owner< shut up!!"
"owner< shut up!!"
```

なおクラス変数を利用するコードを書いたらIDEから非推奨な書き方だと指摘された
Reek Code Smells(笑)
<img width="405" alt="スクリーンショット 2016-07-03 17.04.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/1566f09a-58d1-2d15-f998-49a21da7e3fb.png">

## 10-3.Code smell detector for Ruby
IntelliJ のメッセージで知ったこの規約のようなものは問題あるコードを静的解析で見つけて指摘してくれるツールみたいです。Pythonでいうところのpep8違反を検知するflake8みたいなものなのでしょうか。[ReekCodeSmellに掲載されているExampleのDirtyクラスでの実行結果をみれば、だいたいイメージがつくと思います。パラメータ4個以上ダメとか、変数xダメとか、Booleanパラメータは関数内で処理をswitchしてるからそれなら最初からメソッド分割しろとか...etc](https://github.com/troessner/reek)

<img width="334" alt="スクリーンショット 2016-07-03 17.25.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/e344eb26-dca7-5f12-8c2f-dc289ab37ea8.png">

# 11.RailsにBootstrap3組み込む
CSSテンプレートの中でもBootstrap3はよくできています。簡単にレスポンシブ（ブラウザサイズによって動的にサイトレイアウトが変化するので、スマホとPC両方に対応できる）なWebサイトを構築できるので、よく利用します。ご存知の人も多いと思いますが[Bootstarp3のサンプル実装](http://getbootstrap.com/examples/theme/)をPCで開いて、ブラウザの横幅をマウスで変更すると、いかにレスポンシブデザインが強力か理解できると思います。

## 11-1. Gemfileにbootstrap3を登録
早速RailsにBootstrap3を組み込んでみました( ・ㅂ・)و ̑

```shell-session:Gemfile
# bootstrap3
gem 'bootstrap-sass', '~> 3.3.4'
```

```shell-session:bootstrapインストール
$ gbundler install
```

bootstrap3のjsを組み込みます

```js:app/assets/javascripts/application.js
 //= require jquery
-//= require jquery_ujs
+//= require bootstrap-sprockets
+// = require jquery_ujs
```

最後にsassを新規作成して登録

```sass:app/assets/stylesheets/custom.css.scss
@import "bootstrap";
```

これで Railsにbootstrap3が組み込まれました。


## 11-2.Bootstrap3のコードを書いていく
[Bootstarp3のサンプル実装](http://getbootstrap.com/examples/theme/)を参考にしてゴリゴリ書いていきます。

```rb:app/controllers/tea_controller.rb
class TeaController < ApplicationController
  def index
    render text: 'Hello World hogehoge!'
  end

  def get
    teas = {
        1=>'orange tea',
        2=>'apple tea',
        3=>'japanese tea',
    }
    tea_id = params['id'].to_i
    @tea_id = tea_id
    @tea_name = teas[tea_id]
    @tea_list = teas.values  # 新規に追加した
  end
end
```

```erb:/app/views/tea/get.erb
<h1>Tea Get</h1>
<%= @tea_name %>[<%= @tea_id %>]


<div class="page-header">
  <h1>teas</h1>
</div>
<div class="row">
  <div class="col-md-6">
    <table class="table">
      <thead>
      <tr>
        <th>id</th>
        <th>name</th>
      </tr>
      </thead>
      <tbody>
      <% @tea_list.each_with_index do |tea, index| %>
      <tr>
        <td><%= index + 1 %></td>
        <td><span class="label label-warning"><%= tea %></span></td>
      </tr>
      <% end %>
      </tbody>
    </table>
  </div>
</div>
```

あとはブラウザで開いで確認してみましょう

■ PC向けデザイン(ブラウザの幅によって可変)
<img width="543" alt="スクリーンショット 2016-07-03 23.04.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/b74cf764-0880-81b5-502c-91c905e993fe.png">

■ スマホ向け
<img width="498" alt="スクリーンショット 2016-07-03 23.05.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/65312/cdc3efdb-bb40-b6ae-e00b-d55322a86507.png">




# まとめ Rails至れり尽くせり
いろいろ楽そうなんじゃー _(:3｣∠)＿