Ruby on Rails チュートリアル 第2章 まとめ

##はじめに
Ruby on Railsを最近勉強し始めたので、学んだことを自分なりにまとめておこうと思う。

この記事は基本的に、「[Ruby on Rails チュートリアル（第６版）](https://railstutorial.jp/)」を参考にさせていただき、図や文章などもこのページから引用させていただく。

文中に知らないキーワードがある場合は、その他のサイトから引用する。

##前提知識
このチュートリアルを学ぶにあたって、以下の知識をProgateやUdemyなどで学習した。

- Rubyの基礎
- HTML/CSSの基礎
- JavaScriptの基礎
- Linuxの基礎(コマンドライン)
- Git/GitHubの基礎
- SQLの基礎

##アプリケーションの計画
まず、`rails new`コマンドでアプリケーションの骨組みを生成する。

```
$ cd ~/environment
$ rails _6.0.3_ new toy_app
$ cd toy_app/
```

次に、Bundlerで扱う`Gemfile`を下記のように編集する。

```
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',      '6.0.3'
gem 'puma',       '4.3.6'
gem 'sass-rails', '5.1.0'
gem 'webpacker',  '4.0.7'
gem 'turbolinks', '5.2.0'
gem 'jbuilder',   '2.9.1'
gem 'bootsnap',   '1.4.5', require: false

group :development, :test do
  gem 'sqlite3', '1.4.1'
  gem 'byebug',  '11.0.1', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  gem 'web-console',           '4.0.1'
  gem 'listen',                '3.1.5'
  gem 'spring',                '2.1.0'
  gem 'spring-watcher-listen', '2.0.1'
end

group :test do
  gem 'capybara',           '3.28.0'
  gem 'selenium-webdriver', '3.142.4'
  gem 'webdrivers',         '4.1.2'
end

group :production do
  gem 'pg', '1.1.4'
end

# Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
```

`--without production`オプションを追加することで、本番用のgemを除いたローカルgemをインストールする。
エラーメッセージが出た場合は、`bundle update`を実行する。

```
$ bundle update
$ bundle install --without production
```

Gitでこの`toy_app`をバージョン管理下におく。

```
$ git init
$ git add -A
$ git commit -m "Initialize repository"
```

GitHubで新しいリポジトリを作成し、生成したファイルをリモートリポジトリにプッシュする。

```
$ git remote add origin https://github.com/<あなたのGitHubアカウント名>/toy_app.git
$ git push -u origin master
```

最後に、デプロイの準備をする。
Applicationコントローラ人`hello`アクションを追加し、ルートルーティングを設定する。

```Ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base

  def hello
    render html: "hello, world!"
  end
end
```

```Ruby:config/routes.rb
Rails.application.routes.draw do
  root 'application#hello'
end
```
これらの変更をコミットし、Herokuにプッシュする。
このとき`$$`（アンパサンド演算子）を2つ用いて、GitHubとHerokuへのプッシュを連結する。
この場合、２番目のコマンドは１番目のコマンド実行に成功した場合に限って実行される。
実行時に警告メッセージが表示されることもあるが、今は無視する。

```
$ git commit -am "Add hello"
$ heroku create
$ git push && git push heroku master
```

これで、アプリケーション自体を作成するための下準備が整った、
Webアプリケーションを作る際、アプリケーションの構造を表すための __データモデル__ を最初に作成しておく。
今回は、ユーザーで使うモデルとマイクロポスト(Twitterでいうツイート)で使うモデルを作成する。


##ユーザモデルの設計
ユーザモデルを下図のように構成する。

![users](https://railstutorial.jp/chapters/6.0/images/figures/demo_user_model.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

`users`はデータベースのテーブル(table)
`id`,`name`,`email`の属性はそれぞれテーブルのカラム(column)に相当する。


##マイクロポストモデルの設計
マイクロポストとは、その名の通り比較的短い投稿である。
マイクロポストモデルを下図のように構成する。
マイクロポストとユーザーを関連づける(associate)ために、`user_id`属性も追加する。

![microposts](https://railstutorial.jp/chapters/6.0/images/figures/demo_micropost_model.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)


##Userリソース
ユーザー用のデータモデルを、そのモデルを表示するためのWebインターフェイスに従って実装する。
データモデルとWebインターフェイスは、組み合わさってUsersリソースとなり、ユーザーというものを、HTTPプロトコル経由で自由に作成/取得/更新/削除できるオブジェクトとみなすことができるようになる。
この章のみ、scaffoldジェネレータを用いて生成する。

Railsのscaffoldは、`rails generate`スクリプトに`scaffold`コマンドを渡すことで生成されます。`scaffold`コマンドの引数には、リソース名を単数形にしたもの（この場合は`User`）を使い、必要に応じてデータモデルの属性をオプションとしてパラメータに追加する。
`name:string`と`email:string`オプションを追加することで、Userモデルの内容が設計通りになるようにする。(`id`はRailsによって自動的に __主キー__ としてデータベースに追加されるため不要)

```
$ rails generate scaffold User name:string email:string
```

次に、`rails db:migrate`を実行してデータベースをマイグレート（migrate）する必要がある。
下記のコマンドは、単にデータベースを更新し、`users`データモデルを作成するためのもの。

```
$ rails db:migrate
```

マイグレーションを実行したことで、ローカルWebサーバを別タブで実行できるようになった。
下記のように変更を加え、Cloud9への接続を許可する。

```Ruby:config/environments/development.rb
Rails.application.configure do
  .
  .
  .
  # Cloud9 への接続を許可する
  config.hosts.clear
end
```

次に、Railsサーバを実行する。
これで、ローカルサーバが動作するはず。

```
$ rails server
```


###ユーザページの探検
Usersリソースをscaffoldで生成したことで（2.2）、ユーザー管理用のページが多数追加される。
下記の表のように対応するURLを表示すれば関連するページを表示できる。

|URL|アクション|用途|
|:--|:-------|:--|
|/users|`index`	|すべてのユーザーを一覧するページ|
|/users/1	|`show`	|id=1のユーザーを表示するページ|
|/users/new	|`new`	|新規ユーザーを作成するページ|
|/users/1/edit |`edit`	|id=1のユーザーを編集するページ|

まずはユーザーの一覧を表示する`index`アクションのURL（/users）を見てみる。

![user_index](https://railstutorial.jp/chapters/6.0/images/figures/demo_blank_user_index.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

新規ユーザを登録するために、`new`ページを表示する。

![user_new](https://railstutorial.jp/chapters/6.0/images/figures/demo_new_user.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

NameとEmailを入力して[Create User]ボタンを押すと、`show`ページが表示される。
この時、URLが /users/1 となっているのは、このユーザの`id`が1だから。

![users_1](https://railstutorial.jp/chapters/6.0/images/figures/demo_update_user.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

元のページに戻って`new`ページに再度行けば、ユーザを追加できる。
また、ユーザの削除も[Destroy]リンクをクリックすれば実行できる。

![user_destroy](https://railstutorial.jp/chapters/6.0/images/figures/demo_destroy_user.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)


###MVCの挙動
MVCパターンの観点から考察する。
例として、「/users にあるindexページをブラウザで開く」という操作をした時、内部で何が起こっているのかをMVCで見てみる。

![MVC_example](https://railstutorial.jp/chapters/6.0/images/figures/mvc_detailed.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

1. ブラウザから「/users」というURLのリクエストをRailsサーバーに送信する。
2. 「/users」リクエストは、Railsのルーティング機構（ルーター）によってUsersコントローラ内の`index`アクションに割り当てられる。
3. `index`アクションが実行され、そこからUserモデルに、「すべてのユーザーを取り出せ」（`User.all`）と問い合わせる。
4. Userモデルは問い合わせを受け、すべてのユーザーをデータベースから取り出す。
5. データベースから取り出したユーザーの一覧をUserモデルからコントローラに返す。
6. Usersコントローラは、ユーザーの一覧を`@users`変数（@はRubyのインスタンス変数を表す）に保存し、`index`ビューに渡す。
7. indexビューが起動し、ERB（Embedded RuBy: ビューのHTMLに埋め込まれているRubyコード）を実行して HTMLを生成（レンダリング）する。
8. コントローラは、ビューで生成されたHTMLを受け取り、ブラウザに返す。

このリクエストは、アドレスバーにURLを入力したりリンクをクリックした時に発生する（①）。
リクエストはRailsルーティングに到達し（②）、ここでURLに基づいて適切なコントローラのアクションに割り当てられる（ディスパッチ）。
ユーザーからリクエストされたURLを、Usersリソースで使うコントローラのアクションに割り当てるためのコードは、下記のようになる。
このようなマッピングするコードはRailsのルーティング設定ファイル（config/routes.rb）に書く。

```Ruby:config/routes.rb
Rails.application.routes.draw do
  resources :users # シンボル
  root 'application#hello'
end
```

ルーティングファイルを変更して、サーバのルートURLにアクセスしたら、デフォルトのページの代わりにユーザ一覧を表示するようにする。
つまり、「/」にアクセスしたら /users を開くようにする。
よって、今回のような場合は、Appplicationコントローラ内の`hello`アクションではなく、Usersコントローラ内の`index`アクションを使えるようにする。

```Ruby:config/routes.rb
Rails.application.routes.draw do
  resources :users
  root 'users#index'
end
```

各ページは、Usersコントローラ内のアクションにそれぞれ対応している。
下記は、scaffoldで生成したコントローラの骨格である。
`class UsersController < ApplicationController`という記法では、`ApplicationController`という親クラスから、`UsersController`という子クラスへのクラス継承の文法を使っている。

```Ruby:app/controllers/users_controller.rb
class UsersController < ApplicationController
  .
  .
  .
  def index
    ...
  end

  def show
    ...
  end

  def new
    ...
  end

  def edit
    ...
  end

  def create
    ...
  end

  def update
    ...
  end

  def destroy
    ...
  end
end
```

ページを表示する`index`,`show`,`new`,`edit`以外にも、`create`,`update`,`destroy`アクションがある。


下の表は、Railsにおける __REST__ アーキテクチャを構成するすべてのアクションの一覧である。
RESTは、コンピュータ科学者Roy Fieldingによって提唱された「REpresentational State Transfer」という概念に基づいている。

|HTTPリクエスト	|URL	|アクション|用途|
|:-------------|:----|:--------|:--|
|`GET`	|/users |`index`	|すべてのユーザーを一覧するページ|
|`GET`	|/users/1	|`show`	|id=1のユーザーを表示するページ|
|`GET`	|/users/new	|`new`	|新規ユーザーを作成するページ|
|`POST`	|/users	|`create`	|ユーザーを作成するアクション|
|`GET`	|/users/1/edit	|`edit`	|id=1のユーザーを編集するページ|
|`PATCH`	|/users/1	|`update`	|id=1のユーザーを更新するアクション|
|`DELETE`	|/users/1	|`destroy`	|id=1のユーザーを削除するアクション|

`show`アクションと `update`アクションは、どちらも /users/1 というURLに対応している。
これらのアクション同士の違いは、それらのアクションに対応するHTTP requestメソッドの違いでもある。

ここで、`index`アクションについて整理する。

```Ruby:app/controllers/users_controller.rb
class UsersController < ApplicationController
  .
  .
  .
  def index
    @users = User.all
  end
  .
  .
  .
end
```

`index`アクションの`@users = User.all`という行が、Userモデルからすべてのユーザーの一覧を取り出し（④）、`@users`という変数に保存する（⑤）。
Userモデルの内容は下記にある。
継承によって多くの昨日が備わっており、特に、Active RecordというRubyライブラリのおかげで、`User.all`というリクエストに対してDB上の全てのユーザを返すことができる。

```Ruby:app/models/user.rb
class User < ApplicationRecord
end
```

`@users`変数にユーザー一覧が保存されると、コントローラは下記のビューを呼び出す（⑥）。
`@`記号で始まる変数をRubyではインスタンス変数と呼び、Railsのコントローラ内で宣言したインスタンス変数はビューでも使えるようになる。
この場合、下記の`index.html.erb`ビューは`@users`の一覧を並べ、1行ごとにHTMLの行として出力する。

```Ruby:app/views/users/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Users</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.email %></td>
        <td><%= link_to 'Show', user %></td>
        <td><%= link_to 'Edit', edit_user_path(user) %></td>
        <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New User', new_user_path %>
```

ビューはその内容をHTMLに変換し（⑦）、コントローラがブラウザにHTMLを送信して、ブラウザでHTMLが表示される（⑧）.

###Userリソースの欠点
scaffoldで作成したUserリソースは以下のような問題点を抱えている。

- __データの検証が行われていない__
空欄とか、メアドが変でも通ってしまう。

- __ユーザー認証が行われていない__
ログイン・ログアウトの概念がないので、誰でも操作可能。

- __テストが書かれていない__
scaffoldのテストコードは簡単なテストは含まれているが、データ検証やユーザ認証などの要求を満たしてない。

- __レイアウトやスタイルが整っていない__
ダサいし、使いにくい。

- __理解が困難__
まず、scaffoldの中身がわっっっかんない。


##Micropostsリソース
Userリソースと同様なことを行っていく

###マイクロポストを探検する
Userリソースと同様にMicropostsリソースもscaffoldでコードを生成し、新しいデータモデルでデータベースを更新するために、マイグレーションを行う。

```
$ rails generate scaffold Micropost content:text user_id:integer
$ rails db:migrate
```

これで、Micropostsを作成する準備ができた。
また、下記のようにRailsのrouteファイルが更新され、Micropostsリソース用の`resources :microposts`というルーティングルールが追加された。

```ruby:config/routes.rb
Rails.application.routes.draw do
  resources :microposts
  resources :users
  root 'users#index'
end
```

|HTTPリクエスト	|URL	|アクション	|用途|
|:---|:---|:---|:---|
|`GET`	|/microposts	|`index`	|すべてのマイクロポストを表示するページ|
|`GET`	|/microposts/1	|`show`	|id=`1`のマイクロポストを表示するページ|
|`GET`	|/microposts/new	|`new`	|マイクロポストを新規作成するページ|
|`POST`	|/microposts	|`create`	|マイクロポストを新規作成するアクション|
|`GET`	|/microposts/1/edit	|`edit`	|id=`1`のマイクロポストを編集するページ|
|`PATCH`	|/microposts/1	|`update`	|id=`1`のマイクロポストを更新するアクション|
|`DELETE`	|/microposts/1	|`destroy`	|id=`1`のマイクロポストを削除する|

Micropostsコントローラの構造は`app/controllers/microposts_controller.rb`に書かれており、`UsersController`が`MicropostsController`に置き換わっている以外は、完全に同一。
これは、RESTアーキテクチャが2つのリソースに同じように反映されているから。


###マイクロにする
マイクロになるように文字数制限をかける。
Railsでは、バリデーション(validation)を使って簡単に実現できる。
下記のコードで、140文字に制限する。

```ruby:app/models/micropost.rb
class Micropost < ApplicationRecord
  validates :content, length: { maximum: 140 }
end
```

###異なるデータモデルの関連付
一人のユーザに対し、複数のマイクロポストがあるとする。
UserモデルとMicropostモデルを以下のように更新することで、関連付を表現できる。

```ruby:app/models/user.rb
class User < ApplicationRecord
  has_many :microposts
end
```

```ruby:app/models/micropost.rb
class Micropost < ApplicationRecord
  belongs_to :user
  validates :content, length: { maximum: 140 }
end
```

`microposts`テーブルには`user_id`カラムを作成してあったので、それによってRailsとActive Recordがマイクロポストとユーザーを関連付けることができるようになっている。

![associate_datamodel](https://railstutorial.jp/chapters/6.0/images/figures/micropost_user_association.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

`rails console`コマンドを用いて、ユーザとマイクロポストの関連付けを確認する。
下記のように、操作していく。

```
$ rails console
>> first_user = User.first
   (0.5ms)  SELECT sqlite_version(*)
  User Load (0.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC
  LIMIT ?  [["LIMIT", 1]]
 => #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
 created_at: "2019-08-20 00:39:14", updated_at: "2019-08-20 00:41:24">
>> first_user.microposts
  Micropost Load (3.2ms)  SELECT "microposts".* FROM "microposts" WHERE
  "microposts"."user_id" = ? LIMIT ?  [["user_id", 1], ["LIMIT", 11]]
 => #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 1, content:
 "First micropost!", user_id: 1, created_at: "2019-08-20 02:04:13", updated_at:
 "2019-08-20 02:04:13">, #<Micropost id: 2, content: "Second micropost",
 user_id: 1, created_at: "2019-08-20 02:04:30", updated_at: "2019-08-20
 02:04:30">]>
>> micropost = first_user.microposts.first
  Micropost Load (0.2ms)  SELECT "microposts".* FROM "microposts" WHERE
  "microposts"."user_id" = ? ORDER BY "microposts"."id" ASC LIMIT ?
  [["user_id", 1], ["LIMIT", 1]]
 => #<Micropost id: 1, content: "First micropost!", user_id: 1, created_at:
 "2019-08-20 02:04:13", updated_at: "2019-08-20 02:04:13">
>> micropost.user
 => #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
 created_at: "2019-08-20 00:39:14", updated_at: "2019-08-20 00:41:24"
>> exit
```

###継承の階層
UserモデルとMicropostモデルはいずれも、`ApplicationRecord`というクラスを継承している。
また、`ApplicationRecord`クラスは、Active Recordが提供する基本クラス`ActiveRecord::Base`を継承している。
この`ActiveRecord::Base`という基本クラスを継承したことによって、作成したモデルオブジェクトはデータベースにアクセスできるようになり、データベースのカラムをあたかもRubyの属性のように扱えるようになる。

![inheritance_model](https://railstutorial.jp/chapters/6.0/images/figures/demo_model_inheritance_4th_ed.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

UsersコントローラとMicropostsコントローラはいずれも`ApplicationController`を継承している。
`ApplicationController`が`ActionController::Base`というクラスを継承しており、このクラスは、RailsのAction Packというライブラリが提供しているコントローラの基本クラス。

![inheritance_controller](https://railstutorial.jp/chapters/6.0/images/figures/demo_controller_inheritance.png)
出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)

`ActionController::Base`という基本クラスを継承しているため、モデルオブジェクトの操作や、送られてくるHTTP requestのフィルタリング、ビューをHTMLとして出力などの多彩な機能を実行できるようになっている。
Railsのコントローラは必ず`ApplicationController`を継承しているので、Applicationコントローラで定義したルールは、アプリケーションのすべてのアクションに反映される。

###デプロイ
GitHubにpush

```
$ git status    #追加の前にこうやって状態を確認するのはよい習慣です
$ git add -A
$ git commit -m "Finish toy app"
$ git push
```

Herokuに展開してもいい。

```
$ heroku create
$ git push heroku master
```


##本章のまとめ
- Scaffold機能でコードを自動生成すると、Webのあらゆる部分からモデルデータにアクセスしてやりとりできるようになる
- Scaffoldは何よりも手っ取り早いのがとりえだが、これを元にRailsを理解するには向いていない

- RailsではWebアプリケーションの構成にMVC（Model-View-Controller）というモデルを採用している
- Railsが解釈するRESTには、標準的なURLセットと、データモデルとやりとりするためのコントローラアクションが含まれている
- Railsではデータのバリデーション（validation）がサポートされており、データモデルの属性の値に制限をかけることができる
- Railsには、さまざまなデータモデル同士を関連付けを定義するための組み込み関数が多数用意されている
- Railsコンソールを使うと、コマンドラインからRailsアプリケーションとやりとりすることができる


##個人的にわからなくて調べたキーワード
- __マイグレート__

>SQLを書くことなくRubyでデータベース内にテーブルを作成することができる機能

https://www.transnet.ne.jp/2015/12/29/rails%E5%88%9D%E5%BF%83%E8%80%85%E3%81%8C%E3%81%A4%E3%81%BE%E3%81%9A%E3%81%8D%E3%82%84%E3%81%99%E3%81%84%E3%80%8C%E3%83%9E%E3%82%A4%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%80%8Dcolnr/

- __レンダリング__
Webページにおいて、HTML/CSSやスクリプトによる描画内容・動作の記述や、画像ファイルなど外部データなどを組み合わせ、ブラウザのウィンドウ内にページ内容を描画すること。

- __REST__
>RailsアプリケーションにおけるRESTとは、アプリケーションを構成するコンポーネント（ユーザーやマイクロポストなど）を「リソース」としてモデル化することを指します。
>これらのリソースは、リレーショナルデータベースの作成/取得/更新/削除（Create/Read/Update/Delete: CRUD）操作と、4つの基本的なHTTP requestメソッド（POST/GET/PATCH/DELETE）の両方に対応しています。

出典:[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=6.0#cha-a_toy_app)


##おわりに
この章の内容は図がないとわかりづらいと思ったので、かなり引用させていただいた。
これらの図のおかげで非常に理解がしやすい内容となっていた。