Ruby on Rails チュートリアル 第2章 MVCモデル Usersリソース 継承やDBの仕組みを解説

#近況報告

エンジニア転職成功しました。YouTubeもはじめました。

https://www.youtube.com/channel/UCcXQG8lu_EdyP2Cbhtz1bcA


[前回の続き](https://qiita.com/yuuki_netb/items/67b83fc298f4940cf4a7)

著者略歴
[YUUKI](https://twitter.com/bitcoinjpnnet)
ポートフォリオサイト：[Pooks](https://pooks.herokuapp.com/)
現在：RailsTutorial2周目

#第2章　難易度 ★　4時間
<b>挫折しないRailsチュートリアルの進め方を先にお読みください↓↓</b>

[Railsチュートリアルで挫折しない３つのポイント](https://webnewage.com/rails-tutorial-point)

この章ではRailsの根幹であるMVCモデルについて解説する。

##アプリケーションの計画

###ユーザーのモデル設計

ユーザーという概念をデータモデルで表すと、以下の通りになる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/a3374810-ad47-56ad-7df7-d51455aea22e.png)
出典：[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=5.1#sec-modeling_demo_users)

users = データベースのテーブル
行　=　レコード
列　= カラム
integer = 整数
string = 文字列

idのintegerには重複のない一意のキーを割り当てる。
name,emailのstringにはそれぞれ文字列を割り当てる。
なお、emailはユーザー名としても使われる。

id,name,emailは「属性」と呼ぶ。
integer,stringは「データ型」と呼ぶ。


###マイクロポストのモデル設計

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/b864cf60-5c43-4269-c60f-1e3153eb73ea.png)
出典：[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=5.1#sec-modeling_demo_users)

content = idとマイクロポストのテキスト内容を格納するテキスト
text = テキストを入れるデータ型
user_id = マイクロポストと投稿者を関連付ける属性

##Usersリソース

今回の章ではscaffoldジェネレーターと呼ばれる、Railsに標準装備されているチート機能で生成する。

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

読み方
「scaffoldコマンドでUsersリソースを生成し、name属性、email属性をstring型で定義しますよ」
**scaffoldコマンドの引数にはリソース名を単数形にしたものを使う点に注意**

これを行うことで、「Userモデル」の内容が先程説明した「usersテーブル」のようになる。
idパラメータはRailsによって自動で主キーとして追加される。

次に、データベースをマイグレートする

```
$ rails db:migrate
== 20181201023516 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0015s
== 20181201023516 CreateUsers: migrated (0.0022s) =============================
```

このコマンドで生成したusersデータモデルをデータベースに反映させる。
ここまでできたら、rails serverコマンドで、ローカルでhello worldテキストが表示されているかを確認する。

<img src="https://camo.qiitausercontent.com/556392b0b77d182aaebe5a94902979a46d68a1c8/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3234343633392f37306431333533622d663064632d393235632d616262312d3265383738383336316237312e706e67" height=300px>


###ユーザーページを探検する


scaffoldコマンドを使ったことにより、ユーザー管理用のページが自動生成される。

URLから

/users
/users/new

を辿って見ると、ユーザー一覧、新規ユーザー作成ページが表示されることが分かる。

| URL | アクション | 用途 |
|:--|:--|:--|
| /users | index | すべてのユーザーを一覧するページ |
| /users/1 | show | id=1のユーザーを表示するページ |
| /users/new | new | 新規ユーザーを作成するページ |
| /users/1/edit | edit | id=1のユーザーを編集するページ |
出典：[第2章 Toyアプリケーション](https://railstutorial.jp/chapters/toy_app?version=5.1#sec-modeling_demo_users)

/users/new　から、新規ユーザーを作成してみる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/45291eec-f33d-6fa2-e634-93158159890b.png" height="300px" width="500px">
<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/c57bff47-427a-2fd5-5754-58a7eca4bffd.png" height="300px" width="500px">


こんな感じに作られる。
users/2に表示されている内容はshowアクションの中身である。

今度はeditページを表示してみる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/bf46afda-3a6f-ff2d-4ee7-d9ecc69d30a3.png" height="300px" width="500px">

編集してUpdateしてみる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/6326c0da-b6e8-4048-1df4-8fb60a506d83.png" height="300px" width="500px">

別のユーザーを新規作成してusersページを表示。

<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/89552732-5622-b09c-d7a1-c1fbc39ddbe0.png" height="300px" width="500px">

あとはDestoryして削除してみる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/1c024ea3-a5ff-c0b2-124d-874f99ea7da6.png" height="300px" width="500px">

スッキリ。

このような挙動を作るのは結構大変なんだけれども、こういった仕組みをscaffold commandで一発構築。ただし、初心者はscaffoldに頼ってはいけないとTutorial師匠のお叱りがあるので、これから仕組みを覚えていこう。


##MVCの挙動

Railsの根幹とも言えるMVCの挙動を紹介。
例えば、「/usersにあるindexページをブラウザで開く」という操作をする場合。

これはイメージを頭の中に叩き込んで覚えよう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/b252adfa-5222-5f3b-9abe-213a50eedbb8.png)
出典：[図 2.11: RailsにおけるMVC](https://railstutorial.jp/chapters/toy_app?version=5.1#fig-demo_user_model)

①ブラウザから/usersと言うURLリクエストをRailsサーバーに送信
②/usersリクエストは、RouterによってUsersコントローラ内のindexアクションに割り当てられる。
③indexアクションが実行され、user.rbからUserモデルにuser.allで全てのユーザーを取り出すよう問い合わせる
④Userモデルが全ユーザーをデータベースから取り出す
⑤取り出したユーザー一覧をコントローラに返す
⑥Usersコントローラはユーザーの一覧を@users変数に保存し、indexビューに渡す。
⑦indexビューが起動、ERB拡張子を実行して、HTMLを作成する。
⑧コントローラは、ビューで生成されたHTMLを受け取り、ブラウザに返す。

例えば、routes.rbをこのように変更する。

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

すると、ルートにアクセスするとusersコントローラのindexアクションの中身が表示される。

それ以外にもcreate、update、destroyアクションがあり、これらはページを出力せずに内部で動いている。


ここで、Usersコントローラのindexアクションのコードを見てみる。

```ruby:users_controller.rb
def index
  @users = User.all
end
```

このコードの意味は
「Userモデルから全てのレコードを取り出し、それを@usersと言う変数に代入する」

メソッド内で変数を定義する際は、@を付ける点に注意。
これを「インスタンス変数」と言う。
インスタンス変数には、**initializeメソッドとオブジェクトのインスタンスメソッドだけ**アクセスできる

ちなみに、Active RecordというRubyライブラリのお陰で、userモデルがUser.allというリクエストを実行できる（DBから引っ張ってこれる）


最後に、indexアクションに対応しているviewを見てみる。

```ruby:index.html.rb
  <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>
```

<font color="red">@users.each do |user|</font>の部分に注目。
この部分で、インスタンス変数@usersを読み出し、 each do |user|で、user変数に繰り返し表示している。
user.nameuser.emailでは、User変数の中の名前、メールアドレスを表示している。

|user|の部分はブロックパラメータと呼ぶ。



###Usersリソースの欠点

scaffoldで作成したUsersリソースの問題は以下

- データの検証が行われていない

ユーザー名が空欄だったり、デタラメなメールアドレスでも通る（例えばasdfadsfds←こんなんでも通る）

- ユーザー認証が行われていない

誰でも無制限に操作できてしまう。この問題を回避する為には、ログインログアウト機能を導入する

- テストがお粗末

満足にテストコードが書かれていない

- レイアウトが酷い

見た目がダサいよね。


- 理解が困難

scaffoldで生成されたコードの理解は大変。


これらの問題を、Tutorialを通して解決して学んでいく。


###Micropostsリソース


Micropostsリソースでも同じことをやってみる。

```console
rails generate scaffold Micropost content:text user_id:integer
$ rails db:migrate
== 20181202035043 CreateMicroposts: migrating =================================
-- create_table(:microposts)
   -> 0.0051s
== 20181202035043 CreateMicroposts: migrated (0.0060s) ========================
```

micropostsテーブルが作成された。
ここでroutes.rbを確認。

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

resourcesにmicropostsが追加されている。
このルーティングの意味は、マイクロポスト用のURIをMicropostsコントローラ内のアクションに割り当てる。
ほんとは個別で用意するけどresourcesが自動で割り当てる。

ここで、newページを開いてマイクロポストを作成してみる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/c12ffd26-21f1-f7ce-a084-29028a281ecd.png" height="300">
<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/1bc1e588-6c56-bc9b-2408-af886be462d6.png" height="300">

user_id1が作成したmicropostsページが表示された。

####マイクロポストへのバリデーション

マイクロポストの入力欄の最大文字数を制限する

```ruby:micropost.rb
class Micropost < ApplicationRecord
  validates :content, length: { maximum: 140 }　#contentに入力できる文字数を最大140文字に制限する。
end
```

マイクロポストで141文字以上の文字列を投稿してみる。

<img src="https://qiita-image-store.s3.amazonaws.com/0/244639/16ef104f-6fbd-1a0c-af5a-127f96240514.png" height="300">

文字列が長すぎるとエラーが出る。
先程設定したバリデーションが機能していることが分かる。


###データモデル同士の関連付け

Userモデルと、Micropostモデルの関連付けを行う。

```ruby:user.rb
class User < ApplicationRecord
    has_many :microposts  #Micropostモデルと関連付け
end

```

```ruby:micropost.rb
class Micropost < ApplicationRecord
  belongs_to :user  #Userモデルと関連付け
  validates :content, length: { maximum: 140 }
end
```

has_manyとbelongs_toの**関係性は多重度で言うところの1対多**である。
一人のユーザーに対し、多くの投稿が存在するイメージ。


###Rails Console

ターミナルで`rails console`コマンドを打つと、Railsを実験的に動かすことができる。

今回はDBからuserモデルに格納されている一人目のユーザー情報取り出し、
`first_user`変数に格納する。

```
$ rails c
Running via Spring preloader in process 5117
Loading development environment (Rails 5.1.6)
$ first_user = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
 => #<User id: 5, name: "moku", email: "yuukitetsuyanet@gmail.com", created_at: "2018-12-01 07:10:12", updated_at: "2018-12-01 07:10:12"> 
$ first_user.microposts
  Micropost Load (0.1ms)  SELECT  "microposts".* FROM "microposts" WHERE "microposts"."user_id" = ? LIMIT ?  [["user_id", 5], ["LIMIT", 11]]
 => #<ActiveRecord::Associations::CollectionProxy [#<Micropost id: 4, content: "こらこら", user_id: 5, created_at: "2018-12-02 10:47:21", updated_at: "2018-12-02 10:47:21">]> 
$ 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", 5], ["LIMIT", 1]]
 => #<Micropost id: 4, content: "こらこら", user_id: 5, created_at: "2018-12-02 10:47:21", updated_at: "2018-12-02 10:47:21"> 
$ micropost.user
 => #<User id: 5, name: "moku", email: "yuukitetsuyanet@gmail.com", created_at: "2018-12-01 07:10:12", updated_at: "2018-12-01 07:10:12"> 
2.4.1 :005 > exit
```

初見だと「なんじゃこりゃ！」ってなるかも知れんが実際は簡単なことやってる。

①最初のコマンドで`first_user`変数にuserモデルの一人目のユーザーを代入。
②`first_user.microposts`でid5に関連付いたmicroposts(今回はid4)を読み出す
③`micropost`変数に`first_user.microposts.first`でid4のmicropostsの中にある最初の投稿を代入
④`micropost.user`で「id4の投稿」をしたユーザー情報を表示
⑤`exit`でrails consoleの終了

Rails Consoleからは実際にデータベースを弄る事も可能なので、micropostsを新規作成したり、userを追加したりすることも可能。この辺は都度調べてやってみると良い。


##継承
これまで、UserとMicropostと言う二つのクラスが紹介されたが、この二つはApplicationRecordとは親子関係に当たる。この親子関係は、以下のように表す。

```ruby:user.rb
class User < ApplicationRecord
```

```ruby:micropost.rb
class Micropost < ApplicationRecord
```

さらにApplicationRecordはActiveRecord::Baseを継承している。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/6536efd7-79e7-d077-350d-17506ca95697.png)
出典：[図 2.18: UserモデルとMicropostモデルの継承階層](https://railstutorial.jp/chapters/toy_app?version=5.1#sec-inheritance_hierarchies)

コントローラも同じような親子関係になっている。

```ruby:users_controller.rb
class UsersController < ApplicationController
```

```ruby:microposts_controller.rb
class MicropostsController < ApplicationController
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/244639/045604e8-5ef7-03eb-2888-f5a241cfc88a.png)
出典：[図 2.19: UsersコントローラとMicropostsコントローラにおける継承関係](https://railstutorial.jp/chapters/toy_app?version=5.1#sec-inheritance_hierarchies)

だから何？って話だが、要は親クラスで定義した設定は子クラスでも使えるから、どの子クラスでも扱うような共通事項は親クラスにまとめた方が効率的ですよ、ということ。

この仕組みを「継承」と言う。

継承については第4章で詳解する。


##デプロイ

前回同様、リポジトリをBitbucketとherokuにpushする。
今回の注意点はherokuへのデプロイ。

toy_appを作成してからherokuをインストールしていないので、インストールする。

```
$ source <(curl -sL https://cdn.learnenough.com/heroku_install)
```

で、push後にデータベース起動のコマンドを打つ

```
$ heroku run rails db:migrate
```

これで、heroku open でアプリケーションをひらけばOK。

ちなみに、「なんでherokuインストールしていないのにpushできるねん？」
と疑問思うかも知れないが、herokuのリモートが登録されていればpushできる、ということを覚えておこう。

[第3章へ](https://qiita.com/yuuki_netb/items/55ed4740f12994a42a00)


#単語集

- Usersリソースとは

データモデルとモデル表示の為のWebインターフェイスを組み合わせたもの。
UsersリソースによってユーザーをHTTPプロトコル（ポート番号80）経由で自由にCRUDできる「オブジェクト」とみなすことができるようになる。

- scaffold

自動でCRUDできて、なおかつコントローラー、モデル、ビュー、ルーティングの仕組みを用意できてしまうチート機能。

- CRUD

CREATE/READ/UPDATE/DELETE のまとまりと言えば分かるでしょう。

- パラメータ

メソッドや関数に定義される値のこと。
関数の定義の中で関数に渡す値はパラメータ、関数を呼び出すときに渡す値を引数、と考えると分かりやすい

- 主キー

idに定義されるキー値のトップ。階層構造で言う上の部分。
英語ではprimary keyと呼ぶ
主キーには他のレコードと同じ値になってはならない（ユニークな情報を持っている）ことや、
NULL(空の情報）を登録できないと言う性質がある。
主キーをリレーションシップで外部キーと繋げて、外部の表から情報を読み込んだりする。

- ビルド

ソースコードを書く所から実際のプログラムを作るまでの一連の工程のこと。

- HTTP requestメソッド

HTTPプロトコルでリクエストされるメソッドのこと。

GET
HEAD
POST
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH

などがある。
これらはHTTPサーバーのレスポンスを処理する。

- REST

REpresentational State Transferの略。Webサービスを設計するときのモデルで、以下の原則がある。

- アドレス指定可能なURIで公開されていること
- インターフェース(HTTPメソッドの利用)の統一がされていること
- ステートレスであること
- 処理結果がHTTPステータスコードで通知されること

出典[REST入門 基礎知識](https://qiita.com/TakahiRoyte/items/949f4e88caecb02119aa)

- バリデーション

フォームなどから送信される処理に何らかの制限を加える機能のこと。

具体的には、
①入力内容をチェック
②予め設定したルールに反してないか確認する
③true ルールに合致してれば許可 false ルールに反していれば拒否

このような流れで処理が行われる。

- lengthメソッド


文字列の長さを求めるメソッド。

使い方

```ruby
ruby = "こんにちは"　#rubyに文字列"こんにちは"を代入する。
ruby.length()    #rubyに格納されている文字列の数を表示する
 => 5
```


- オブジェクト指向とは？

RubyやJavaの言語のそもそもの仕組み。いわゆる「物」を基準に考えることで、オブジェクト指向のプログラミング言語には以下のような特徴がある。

- オブジェクト指向（OOP）
 - クラスやインスタンスの存在
 - 継承
 - カプセル化
 - 多相性

参考：[初心者向けに徹底解説！オブジェクト指向とは？](https://eng-entrance.com/what-oop)