おっさん初学者のRailsチュートリアル学習記録(6章)

プログラミング年少組のど素人が、アウトプット用に素人目線の解説を書いていきます。
自分が自分に教えていることを想像しながら進めていきます。
下記と同じような境遇の方であれば参考になるかも

- まっさらなプログラミング初学者目線
- オール独学
- 勉強は得意じゃない
- 社会人のため、1日に勉強できる量は限られる。

電子書籍のwebテキスト(第６版)を購入して使用
Progateの「Web開発パス」完走済
ドットインストールのプレミアム会員卒業
Railsチュートリアル解説動画を見ながら学習中
#6章#
6章ではユーザー登録ページを作ります
チュートリアルでもここから難易度が徐々に上がっていくみたいです・・・と、いうことは・・・これまでは難しくなかったということですね・・・ふう〜〜

骨組みは5章の最後に作ったusersコントローラーやビューを使用します
そして、この章ではデータモデルの作成やデータを保存する手段のを学びます。
ユーザーが名前や個別の情報を保存できるデータベースに各々のデータを登録できるようにして、尚且つプロフィールのページも作ります。
その後、登録するデータのルールを決めたり、データの中でも慎重に取り扱わないといけないパスワードについても見ていきます。
頑張っていきましょう
#6.1 Userモデル#
*データベース連携のために必要な機能について*

6章では最初にデータベースやデータベースとの連携について学んでいきます。
Railsでは、データモデルとして扱うデフォルトのデータ構造のことをモデル（Model）と呼びます。**MVCのM**です。データベースを使ってデータを長期間保存します。
そうすることで、パソコンの電源を切ったり、ログアウトしたりしても、自分の登録のメールアドレスやパスワードを入力することでログインし、自分専用のログイン画面を呼び出すことができるようになります。

Railsではデータベースとのやりとりにおいては<font color="red">**Active Record**や**マイグレーション（Migration）**</font>などの機能を使用します

**Active Recordとは**
急ですが、データを保存するデータベースは外国にあるとイメージしてください・・・
※あくまでイメージの話です！！
そこにあるデータベースに対してモデルから命令を行って、データの新規作成/保存/検索などの機能を使うことになるのですが、いかんせん外国なので言葉の壁があります。プログラミングで言う別の言語（SQL）です。
データベース使うために新しく言語勉強するのか〜・・と肩を落としてしまいそうですが・・
そこで登場するのがRailsの機能である「Active Record」ということになります。
Active Recordは、データオブジェクトの作成/保存/検索などのデータベース向けのやり取りを<font color="red">「Ruby」の言語のメソッド</font>で可能にしてくれる「翻訳こんにゃく」みたいなものです。
なので、データベースを使うのに必要なSQL（他の言語）を意識する必要はありません

**マイグレーション（Migration）とは**
データベースに保存するデータの定義をRubyのコードで記述してまとめたものです。

Railsは、この２つの機能を使うことで、データベースの細部をほぼ完全に隠蔽し、切り離してくれるので、データベースのことを細部までマスターしていなくてもデータベースを使えるようにできています。

今回の章で使用するトピックブランチを作成しましょう

```
$ git checkout -b modeling-users
```
##6.1.1 データベースの移行##

Railsではデータを保存する場所としてデータベースを利用することは先ほど説明しました。
このデータベースは「テーブル」と呼ばれます。
よって、この章で使うユーザーに関するデータを入れるデータベースは「usersテーブル」となります。
この「userテーブル」に入れるデータの項目は、「name」「email」です。後で「password」が出てきます。
普通サイトに入会する時は「名前」「email」「パスワード」は必ず入力する項目にありますもんね。

**Usersモデルを生成する**
モデルを生成する方法は、コントローラー同様**「rails generate」コマンド**を使用します

```
$ rails generate model User name:string email:string
```
※同じ「rails generate」でもモデルは**単数形**になってますが、ここはひとまず「モデル＝単数形」「それ以外＝複数形」で覚えときましょう


「rails generate model」コマンドを実行すると２つのファイルが作成されます
それが**「モデル（`user.rb`）」と「マイグレーションファイル（`タイムスタンプ_create_users.rb`）」**です。

**マイグレーションファイルについて**
マイグレーションファイルはここにあります👉db > migrate

```_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end
```
「rails generate」コマンドで指定した通りに、「string型のnameとstring型のemailをusersテーブルを作ってね」ということが何となく読み取れます。。ふむふむ。
ご覧の通り**「cange」メソッド**が定義されています。
これは読んで字のごとくデータベースに与える変更を定義します。

そんなこんなで、「name」と「email」の2つの項目を持った「users」テーブルが完成しました。
が、実はテーブルを作ると勝手に作られる項目があります。それが「id」「created_at」「updated_at」です。何もしてないのに魔法のように現れるので**マジックカラム**と呼ばれます。
これは、他にテーブルを作った時にテーブル同士を紐付ける時に大変役に立ちますし、重要度も高いので、テーブルを作成した際は**必ず**付随して付けられます。
よって、「usersテーブル」には「name」「email」にマジックカラムの「id」「created_at」「updated_at」の3つを加えた５つの項目がある！ということになります。

さてさてお次が仕上げとなります。
それが**「マイグレーションの適用」**です

```
$ rails db:migrate
```
すごい見覚えあるのですが、2章で出てきてました。あの時確か6章で説明するとか何とか言っていたような・・・
とりあえずこのコマンドを実行すると
「db/development.sqlite3」というファイルが生成されます。（ここに👉db > migrate）
テキストにある通り、このファイルをパソコンにダウンロードして見てみると・・・
先ほどの「usersテーブル」がちゃんとできているではありませんか

結果として、
「rails generate」だけではテーブルの生成までは至らなくて「rails db:migrate」を実行することで、テーブルの形として出来上がる！ということだったんですね。
##6.1.2 modelファイル##
*モデルファイルをのぞいてみる*

「rails generate model」コマンドを実行した時にマイグレーションファイルと一緒に生成されるファイルが**「user.rb」ファイル（モデルファイル）**です
ここにできています👉 app > models > concernsの中

開いてみると・・・UserクラスがApplicationRecordクラスを継承している。とだけ記されたシンプルすぎる内容となってます。
継承しているため、ここには何も書いていませんが、後で出てきます「User.first」や「User.all」などの、データを取り出すメソッドが『定義されている様子もないのに』、使えるようになっています。

ちなみに、「ApplicationRecord」クラスは「ActiveRecord::Base」クラスを継承しています
（コンソールを開いて、「.superclass」を付けたら出てきますよね）
次回よりこの「ActiveRecord::Base」クラスでできることを学んで、モデルファイルでできることの深層を掴んでいきます
##6.1.3 ユーザーオブジェクトを生成する##
*データベースへのデータの生成と保存の流れを見ていく*

４章同様に、データを保存していく流れをRailsコンソールを使って実験的に見ていきましょう。
今回はデータベースの内容まで変更したくない時のためにある**サンドボックスモード**なるものを利用します

```
$ rails console --sandbox
```
これでコンソールを起動すると、終了時にこの中で作ったデータは取り消されるようになります。

おさらいですが、新しいユーザーを登録する時は

```
User.new
```
でしたよね。こうするとどこのカラムにも何のデータも入ってない情報が返ってきます

```
>> User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>
```
全部「nil」です・・・4章で、初期化のハッシュをとる例をやりました・・・うっすら覚えてるような覚えてないような・・・
まあ、今回同じ原理がActive Recordにも取り込まれているということみたいです。

さてこれからデータを入れていきましょう

```
>> user = User.new(name: "Michael Hartl", email: "michael@example.com")
```
これで「name」と「email」が入ります。
※「id」「created_at」「updated_at」はまだですよ〜〜
今は「こんな感じでデータベースに保存しようかと思うとりま〜〜〜す」という状況です。
ですので、**「まだ」**保存されておりませぬ
ただ、ここで保存しようとするデータが適正かどうかを確認する（有効であるデータかどうか確認する）ための「valid?」というメソッドがあります。

```
>> user.valid?
true
```
こんな風に、「valid?」に確認してもらって「true」が返ってきたら、適正なデータであるという証拠です

それではちゃんとしたデータであるとチェックも入ったことですしこれを保存することにしましょう。
先ほどと同様に「save」メソッドを使います

```
>> user.save
```
これで最終的に「true」が返ってきたら保存は完了します！「保存確定で〜〜〜す」となります。
確定しましたので「id」「created_at」「updated_at」にも値が入ります。
また、ちゃんと入っているかの確認も簡単にできちゃいます

```
>> user.name
=> "Michael Hartl"
>> user.email
=> "mhartl@example.com"
>> user.updated_at
=> Mon, 23 May 2016 19:05:58 UTC +00:00
```
ただ、毎回このように「こんな感じでデータベースに保存しようかと思うとりま〜〜〜す」（モデルの生成）→「保存確定で〜〜〜す」（モデルの保存）の2段回にするのは面倒臭いです。そんな時こそ<font color="red">「Active Record」</font>です！！
**「User.create」**を使います

```
>> foo = User.create(name: "Foo", email: "foo@bar.com")
```
こんな風に使うことで「生成」と「保存」を一気にできちゃいます！
また、消したい時は「destroy」すれば良いのです。

```
>> foo.destroy
```
##6.1.4 ユーザーオブジェクトを探索する##
*Active Recordを使ってデータの内容を確認する*

Active Recordを使ってデータベースの中身を確認することができます。
①まずは「idから」データを引き出すもの

```
>> User.find(1)
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com",
created_at: "2019-08-22 01:51:03", updated_at: "2019-08-22 01:51:03">
```
findの( )に指定したidのデータを取り出していますね。

②属性を指定してデータを引き出すもの

```
>> User.find_by(email: "michael@example.com")
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com",
created_at: "2019-08-22 01:51:03", updated_at: "2019-08-22 01:51:03">
```
find_byの( )に取り出したいデータが持っている内容を入れ、該当するデータを取り出していますね。

③データベースにある最初のidのデータを引き出すもの

```
>> User.first
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com",
created_at: "2019-08-22 01:51:03", updated_at: "2019-08-22 01:51:03">
```
最初のデータはidが1なのでそれを取り出しています

④データベースに入っている全てのデータを取り出すもの

```
>> User.all
=> #<ActiveRecord::Relation [#<User id: 1, name: "Michael Hartl", email:
"michael@example.com", created_at: "2019-08-22 01:51:03", updated_at:
"2019-08-22 01:51:03">, #<User id: 2, name: "A Nother", email:
"another@example.org", created_at: "2019-08-22 01:53:22", updated_at:
"2019-08-22 01:53:22">]>
```
とにかく全部出したい！全部見たい！という場合に使われそうです
##6.1.5 ユーザーオブジェクトを更新する##

いったん登録したユーザーネームやemailを変更したーいなんて場面は必ず訪れます。
今回はその変更方法を見ていきましょう

・変更方法その１
そのままuserオブジェクトに変更した値を入れるパターン

```
>> user.email = "mhartl@example.net"
=> "mhartl@example.net"
```
今回は変更した値をデータベースに「保存」するわけですから、あれが必要になります
そう、**<font color="red">save</font>**　です

```
>> user.save
=> true
```
これをしない限りは、データベースの内容は変わりませんのでご注意を！
今回は、元々登録されていたデータを「更新」したわけですので、マジックカラムの「updated_at」の日付が変わることになります（「created_at」はもちろんそのままです）

```
>> user.created_at
=> Thu, 22 Aug 2019 01:51:03 UTC +00:00
>> user.updated_at
=> Thu, 22 Aug 2019 01:58:08 UTC +00:00
```
まあ、そうですよね。

・変更方法その２
「update」を使います

```
>> user.update(name: "The Dude", email: "dude@abides.org")
=> true
>> user.name
=> "The Dude"
```
先ほどとの1番の違いは**saveがいらない**という部分ですね。これだけでデータベースに「保存」まで完了してしまうところです。めでたしめでたしはい次いきましょう・・・とはいきません
updateでは「name」も「email」も一気に変更しましたが、もし、**個別のデータを更新したい場合は「update_attribute」**を使いましょう！
ということになっています

```
>> user.update_attribute(:name, "El Duderino")
=> true
>> user.name
=> "El Duderino"
```
こちらももちろんsaveは必要ありません。
update_attribuleは引数を2つ持ちます。一つ目が「:name」。二つ目が「"変更した値"」となっています。それぞれを「キー」と「値」として見るとわかりやすいかもしれませんね。
#6.2 ユーザーを検証する#

**モデルのバリデーション機能をテストする場合はテスト駆動開発が適しています**
（バリデーション機能とは登録するデータのルールを決めるニュアンスの機能です）
モデルこそが、「テスト先に書くよね」の典型です
テスト駆動開発をおさらいしますと
①失敗するテストをかく
②テストを成功させるように実装する
③テストが成功する
といった流れで進めていくものでした。

**これからの流について**
1.まず有効なモデルのオブジェクトを作成します
2.成功時の状態に対してもテストを書いておき最初のモデルが有効であるかどうかも確認しておきます
3.属性のうち1つを有効でない属性に意図的に変更します
　（nameが空白だとか、emailのフォームがあってないとか）
4.バリデーションで失敗するかどうかをテストする


**どこの部分でモデルのテストを実施するのか**
「rails generate model」のコマンドでモデルのテストファイルができています
気付きませんでしたすみませんでした
ここにできている　👉 test > modelsの中

**setupメソッドという特殊なメソッドについて**
setupメソッド内に書かれた処理は、<font color="red">各テストが走る直前に実行されます</font>
`@user`はインスタンス変数ですが、setupメソッド内で宣言しておけば、すべのテスト内でこのインスタンス変数が使えるようになります。
まあ、`@user`とはこういうものですよーと最初に定義しておくことで、その後がラクですし、コードもすっきりしますしね。

さてさて、作成したコードが以下の内容です

```test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "should be valid" do
    assert @user.valid?
  end
end
```
`@user`はインスタンス変数ですが、名前とemailが入れられています。
「valid?」メソッドで`@user`が有効かどうかが確認されていますが、「このデータは保存するのに有効ですか？」というニュアンスのテストです。今のところ何のバリデーションの設定（値のルール）を設けていませんのでこのテストは成功します。

ちなみにテストを実施する場合は以下のコマンドを選択することで、モデルのテストのみ実施できます

```
$ rails test:models
```
以前紹介された「rails test:integration」と同じような感じですね
##6.2.2 存在性を検証する##
*presenceで空白に規制をかける*

最も基本的なバリデーションはまさに「存在性（Presence）」でしょう
値が存在するかどうかを確認します。

ではまず失敗するテストから書いていきましょう

```test/models/user_test.rb
def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "should be valid" do
    assert @user.valid?
  end

  test "name should be present" do
    @user.name = "     "
    assert_not @user.valid?
  end
```
先ほどの内容に一番下のやつを追加した形ですね

```
@user.name = "     "
```
これで「name」に「"Example User"」が入っていたのを「空白」にしちゃいます
その上で、

```
assert_not @user.valid?
```
assertにnotがついてるから「〜ですよね？」から「〜ではないですよね？」という意味合いにしてるのかな・・・
まとめると「`@user`は有効ではないですよね？」ということを表しているのでしょう

ここで確かめてみましょう

```
$ rials test:models
```
・・・失敗！！
そりゃそうです。まだ何も規制かけてないですもん。
「name」が空白だから有効ではないなんてルールはどこにもありませんから。
「空白だから有効じゃないですよね？」なんて聞かれても「いやいや有効ですがな」と返ってくるのは当たり前です。

さてさて、それなら規制をかけて「空白なら有効ではない！」というルールを作っちゃいましょう！
ルールは先ほど確認したらもぬけの空だった**userモデル**に書いていきます

```app/models/user.rb
class User < ApplicationRecord
  validates(:name, presence: true)
end
```
ここにある**「validates」メソッド**こそが規制を設ける時に使うメソッドになります
※validatesとは「検証」という意味です。検証し、クリアできなければfalseを返すという意味で規制です
「presence: true」
ここで冒頭で紹介した「Presence（存在性）」が登場しました
validates(:name, presence: true)とは
「name」には存在性がtrue（ある）かどうかを「validates（検証）」しまーす、ということだったんですね

そうです。ここで新たなルールが誕生しました。
**「name」は存在しないと「検証」をクリアできずに「folse」を返す**というものです

試しにrails consoleを試してみると

```
$ rails console --sandbox
>> user = User.new(name: "", email: "michael@example.com")
>> user.valid?
=> false
```
ちゃんと「false」が返ってきてますね。よしよし。
有効ではないデータはもちろん「保存」もできません

```
>> user.save
=> false
```
それではもう一度userモデルのテストに戻ってみましょう

```test/models/user_test.rb
test "name should be present" do
    @user.name = "     "
    assert_not @user.valid?
  end
```
これは「空白だから有効じゃないですよね？」を確認してるやつでしたが
今回は、「name」は存在しないと「検証」をクリアできずに「folse」を返す」というルールが加わっていますので、「そうです！有効じゃないやつです！空白はダメです！」という結果になります
よってもう一度テストをすると、今度はクリアします

```
$ rails test:models
```
同様にして「email」についても作っていきましょう
まず、失敗するテストを作って

```test/models/user_test.rb
 test "email should be present" do
    @user.email = "     "
    assert_not @user.valid?
  end
```
失敗することを確認したら、通るために必要な設定を組み込んで

```app/models/user.rb
validates :email, presence: true
```
最後に今度は成功することを確認する

```
$ rails test
```
これで「存在性」については理解できました。めでたしめでたし
##6.2.3 長さを検証する##
*lengthを使って長さの規制を加える*

「名前」や「email」が空白だった場合に規制をかけました。
今度は、長すぎる名前やemailにも規制をかけちゃいましょう
今回定めるルールは以下とします。。。根拠はないけど。もっと長い名前の人がいたらごめんなさい
「name」：50文字まで
「email」：255文字まで

とりあえず失敗するテストから書いていきましょう

```test/models/user_test.rb
  test "name should not be too long" do
    @user.name = "a" * 51 # 51文字以降が失敗
    assert_not @user.valid?
  end
  
  test "email should not be too long" do
    @user.email = "a" * 256 # 256文字以降が失敗
    assert_not @user.valid?
  end
```
51文字の「name」なんてダメっすよね？
256文字の「email」なんてダメっすよね？
なんてことを聞かれても、「そんなルールねーから知らねーよ。出直して来い」
と、失敗を返されます。
ちなみに51文字や256文字を入力するのはめんどいので、"a"という文字列「*（かける）」数字ということで、すっきりした書き方になってます。

それではまたuserモデルに「validates（検証）」を利用して規制をかけて、テストをサクセスさせましょう！！

前回は「presence（存在性）」を使用しました。
今回は**「length: {maximum:  }（長さの上弦じゃなくて上限）」**を使用します
見たまんまですね

```app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 }
end
```
こちらの方が見やすいのでこうしときましょう

```app/models/user.rb
class User < ApplicationRecord
    validates :name, presence: true,
                       length: { maximum: 50}
    validates :email, presence: true,
                        length: {maximum: 255}
end
```
同じ属性はこのように「 ,（コンマ）」で区切って繋げて書くことができます

今度は「「name」は文字数が50文字までじゃないと「検証」をクリアできずに「folse」を返す」
「「email」は文字数が255文字までじゃないと「検証」をクリアできずに「folse」を返す」
なんてルールが加えられました

よって再度テストしますと
51文字の「name」なんてダメっすよね？
256文字の「email」なんてダメっすよね？
という問いには
あたりめーだ！「name」で50超えてるなんてダメに決まってるだろうが〜〜
あたりめーだ！「email」で255超えてるなんてダメに決まってんだろうが〜〜
ということになり。テストはサクセスします！！
これが、長さの検証です
##6.2.4 フォーマットを検証する##
*メールで入力する内容をパターン化する*

ここでは「email」に適切なパターンでないと検証をクリアできないように規制を加えます
決まった型じゃないパターンを弾くという「検証」を入れてくということでしょうけども、そんなの無限にあるし例をあげるのも限界が・・・とりあえず見ていきましょう

まずはおさらいから
文字列の配列を簡単に作れる<font color="red">%w[ ]</font>という便利なテクニックを覚えているでしょうか
[ ]の中に空白で区切って文字列を並べると、配列にしてくれるやつです

```
>> %w[foo bar baz]
=> ["foo", "bar", "baz"]
```
これを変数addressesに代入してeachメソッドで一つずつ出していきます

```
>> addresses = %w[USER@foo.COM THE_US-ER@foo.bar.org first.last@foo.jp]
=> ["USER@foo.COM", "THE_US-ER@foo.bar.org", "first.last@foo.jp"]
>> addresses.each do |address| # |address|はブロック変数
?>   puts address
>> end
USER@foo.COM
THE_US-ER@foo.bar.org
first.last@foo.jp
```
テストはこれを利用して書いていきます

話を戻して、メールアドレスのバリデーションについては、これまでのものと違って扱いが複雑です。。。
①有効なメールアドレスが通ることを確認することと、②無効なメールアドレスが弾かれることを確認しながら進めていきます。
まずは①有効なメールアドレスが通ることを確認することからです

```test/models/user_test.rb
  test "email validation should accept valid addresses" do
    valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
                         first.last@foo.jp alice+bob@baz.cn]
    valid_addresses.each do |valid_address|
      @user.email = valid_address
      assert @user.valid?, "#{valid_address.inspect} should be valid"
    end
   end
```
ひと目見て「うっ・・」となりそうですが、一つ一つ見ていけば何てこたないです。。
1.変数「valid_addresses」に今回有効とするアドレス４つを記した配列を代入する
2.eachメソッドで「valid_addresses」から一個ずつ出しては、「valid_address」に入れていきます
3.今度はそれを@user.emailに入れていきます
4.最後に`@user`はメールアドレスも含めて有効ですよね？という確認をする
・・・まあ、簡単に言えば「このアドレス有効っすかー？」を４回繰り返しています。
このくだりは何度もやってきましたが、まだ何の制限もかけてないのでどんなアドレスも有効とされるので「そっすねー有効っすー」となってテスト自体はサクセスです。
①有効なメールアドレスが通ることを確認するので当然っちゃー当然です

ここで気になるのがこの部分です

```
"#{valid_address.inspect} should be valid"
```
うわっ何か難しそうなのがひっついとる！と引いちゃいましが、これは4つ繰り返す中でどのメールアドレスで失敗したのかを特定してくれる便利なやーつーです。・・・詳しい仕組みは・・・わかりません。。。

お次は②無効なメールアドレスが弾かれることの確認に移ります

```test/models/user_test.rb
  test "email validation should reject invalid addresses" do
    invalid_addresses = %w[user@example,com user_at_foo.org user.name@example.
                           foo@b
ar_baz.com foo@bar+baz.com]
    invalid_addresses.each do |invalid_address|
      @user.email = invalid_address
      assert_not @user.valid?, "#{invalid_address.inspect} should be invalid"
    end
  end
```
先ほどとほぼ同じですね。変数の名前をvalid（有効）としていたのをinvalid（無効）に変えたくらいでしょうか。
今度は「assert_not」を使ってますので、「こんなん有効じゃないっすよね」と確認しています。
さっきと同様何の規制もかけてないので、「いやいや有効っすよ」となり、テストは失敗します

それではこのテストが成功するように、バリデーションで無効な表現に規制をかけていきまっしょい

**正規表現**
メールアドレスで、「これはいい、これはダメ」を検証するためには**「format（オプション）」**というものをバリデーションで用います

```
validates :email, format: { with: /<regular expression>/ }
```

`<regular expression>`に書かれてあるパターンに合致してたらOKとして、そうでなければNGといったタイプの規制方法となります

ここでは<font color="red">〜正規表現：Regular Expression〜</font>と呼ばれる技術を使用します
一応使うだけ使いすが、これがいったい何なのかを調べ出したら奥が深すぎて沼にハマること間違いなしです。。
ですので、今回はさわりのさわりの部分を使って答えとやり方と雰囲気だけ覚えときましょう・・・
※ちなみに[Rubular](https://rubular.com/)というサイトを使えば、体系的に正規表現について学ぶことができます

今回正しいメールアドレスの正しい表現として使うパターンとなるものがこちらです

　　<font color="red">**/\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i**</font>
・・・おやすみなさい。。と、反射的にまぶたが落ちそうな文字の羅列ですが
ここしか出てこないですし、せっかくなので分解しちゃいましょう。
**「 / (スラッシュ)」**
とりあえず正規表現はこれで始まり、これで終わります
**「 \A 」**
これが文字列の先頭
**「 \z 」**
逆にこちらは文字列の末尾（なぜかこちらは小文字・・・）

と、いうことは
「/\A〜〜\z/」で表現される「〜」の部分が正しい文字列のパターンを表しているのだなふむふむ。

**[\w+\-.]**
`user@example.com`で言えば「user」に該当する部分です
ここでは英数字、アンダースコア（ _ ）、プラス（+）、ハイフン（-）、ドット（.）のどれでも良いので少なくとも1文字以上使って入力します...（ _ ）ってどこからきたんだろう...

**@**
`user@example.com`で言えば「@」に該当する部分です。まんまですね

**[a-z\d\-.]**
`user@example.com`で言えば「example」に該当する部分です。
英小文字、数字、ハイフン、ドットのいずれかを少なくとも1文字以上使って入力します

**`\.`**
`user@example.com`で言えば「 . (ドット)」に該当する部分です。

**[a-z]**
`user@example.com`で言えば「 com 」に該当する部分です。
英小文字を少なくとも1文字以上で入力します

最後は**「 i 」**です
これは、最終的に大文字でも小文字でもどっちでもええよ。ということを表しています

・・・分解してみると、どこの部分がどこのことを表しているかが見えてきますね。どう書けば、何が許可するようになるかなど、たくさんルールーがあってまさに「沼」です。
恐るべし「正規表現」・・・

と、いうわけでこちらをモデルに投入しますと

```app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX }
end
```
一瞬、「えっ」となりますが、一度定数に代入して、先ほどの`/<regular expression>/`にその定数を入力しています。そのまま入れるのかな〜と予想していましたので混乱しますよね。
ちなみにそのまま入れてもテストは通りました

```app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
end
```
こっちの方が分かりやすい気もしますが何か理由があるのでしょう！！

ここまでかなりボリューミーになりましたがフォーマットの検証は以上です
##6.2.5 一意性を検証する##
重複をチェックして被ってたらNGにする検証についてです
よく、登録しようとしたら「このアドレスはすでに使われてます」なんてエラーが出ることありますよね。あれまさにバリデーションで一意性を検証しているということなのでしょう！！
テキストではここで<font color="red">**「重大な警告があります」**</font>なんて書いてあります。警戒して読み進めていきましょう。

一意性のテストのためには、メモリ上だけではなく、実際にレコードをデータベースに登録する必要があります。実際にデータ上にあるもののダブってないかをチェックするためでしょうね。
とりあえずコードから見ていきましょう

```test/models/user_test.rb
  test "email addresses should be unique" do
    duplicate_user = @user.dup
    @user.save
    assert_not duplicate_user.valid?
  end
```
`@user.dup`ってなん？て感じですね

dupとは
同じ属性を持つデータを複製するためのメソッドです

このテストではとりあえず`@user`データをdupメソッドで複製して「dupulicate_user」に入れます
（「dupulicate_user」の中にはsetupで指定した`@user`のデータが入ってます）
その後、**「@user.save」で`@user`をデータベースに保存しちゃいます**
ここがこれまでになかったパターンですよね。あくまでサンプルで使ってたものを実際に保存しちゃってます。
そして、データベース上にsetupで指定した`@user`のデータある状態で、
「複製した「dupulicate_user」は「有効」じゃないっすよね？」（assert_notなので否定です）
と確認しているわけです

ここでテストを実施しますが
いつもの流れで、「そんなん無効なんてルールはねえよおとといきやがれ」と突き返されます

じゃあルールを作ればいいのだな。
ということでバリデーションです。userモデルを開きましょう

```app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX }, # 「,」を忘れずに
                    uniqueness: true # ここが追加されただけ
end
```
これで「emailは唯一無二であること（同じものがないこと）」を検証するルールが加わりました

また、「メールアドレはス大文字、小文字を変えても同じものと見なす！」性質を忘れてはいけません。
このままだと、`foo@bar.com`と`FOO@BAR.COM`が違うアドレスとみなされて通っちゃいます。
それはいけません！
そのためにテストにこれを追加します

```test/models/user_test.rb
duplicate_user.email = @user.email.upcase
```
こうすることで、複製された方のemailを巨大化しているのです
最終的に、普通サイズの`@userのemail`と巨大化されたduplicate_userのemailを比べていることになります

一応これでまたテストができましたので、お決まりのくだりです
「有効じゃないっすよね」→「おとといきやがれ」→「バリデーションの更新」
先ほどの「唯一無二であること」のところをチョチョイと変えます

```
uniqueness: { case_sensitive: false }
```
「true」がどっか行っちゃいましたけども・・・
（「case_sensitive」を調べてみると・・・**「大文字と小文字を区別する」**というそのまんまの回答がありました）
それが「false」なので「大文字と小文字をバラバラに見るなんて認めねえからな！」ということでしょうか
ちなみにこれを判断する中でついでに消えてしまった「true」も見ているみたいです・・・

そんなこんなで、一意性の検証も完成です
最後にテストしときましょう・・・もちろん<font color="green">「サクセス！！」</font>

**落とし穴**
そんなこんなで「一意性」は終わり〜というわけではないみたいです。そんな甘いものではなかったか・・・クソ〜
**Active Recordはデータベースのレベルでは一意性を保証していない**という問題があると言ってます

具体的に言うと
1.登録の際に、登録完了ボタンを勢いよく「カチカチッ」と押します（押すなよ！）
2.そうすると2回同じデータを飛ばしたことと同じ現象が起きます（言わんこっちゃない）
3.同じデータがきても「一意性」のバリデーションで弾かれるから問題ないか〜と楽観視する
4.そうやって油断してると、2つ目が弾かれずに両方保存されちゃってる現象が起きる

Railsの方で一意性の検証をしていても、データベース側ではこういったケースをスルーしてしまうみたいです。
変な感じですよね。そんなことで例外が発生しちゃうとはデータベースもまだまだですね。
この問題にはデータベースに**「インデックス」**をつけて対処します！！

**インデックスとは・・**
市場の動きを示す指標・・ではなくて、「索引」のことです。本の最後についてる、「あ」が頭につく用語はこれ、「い」が頭につく用語はこれ、「う」が頭につく用語はこれ・・・・・・・・という

このインデックスはデータベースからデータを取り出すときに大いに役立ちます
先ほどデータベースからデータを取り出すケースで「fing_by( )」を使用しました。
この( )内に入る属性を指定して探し出す流れでしたが、インデックスを指定していなかった場合、データベースの全体から探さなくてはなりません。
インデックスを指定していると、格納場所を絞った上での検索が可能になるため検索時間の大幅短縮になります。

**どこにどうやってインデックスを加えるの？**
インデックスを加えるのは「データベース」です。
データベースの変更を行うのはもちろん「マイグレーションファイル」です
今回新たにマイグレーションファイル「のみ」を作成しますので以下のコマンドとなります

```
$ rails generate migration add_index_to_users_email
```
「rails generate migration」はこれまでの「rails g」とは違って複数のファイルはできません
マイグレーションファイルができたら早速編集しましょう

```db/migrate/[timestamp]_add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[6.0]
  def change
    add_index :users, :email, unique: true
  end
end
```
おなじみの「change」メソッドでデータベースの変更を加えます
add_indexというのはRailsのメソッドです。
「users」テーブルの「email」カラムに**「unique: true」**という設定を入れています

Rails側ではemailで「uniqueness: true」を入れて一意性の設定したんで、データベース側でもインデックスを貼って一意性の設定してくださーい・・・ということみたいです。

まだまだ続くぜ
ここでいきなりテスト用のサンプルデータの入った**「fixtures」**とかいうファイルが登場します
これは「rails generate model」した時に自動で作られます
setupで一個作りましたが、テストやるためにもっとデータがあったらなーて時はこちらを使用します
ここにあります👉test > fixtures > filesの中

```test/fixtures/users.yml
one:
  name: MyString
  email: MyString

two:
  name: MyString
  email: MyString
```
テスト用のデータということは、このデータを使ってテストをするということでしょうか・・・
それだったら、これまでのユーザーのアドレス関連のテスト全部失敗するやん。「email: MyString」とか正規表現のかけらも合ってないやん。どうなってんねん
それは・・・
「fixture内のサンプルデータはバリデーションを通っていなかったので今まで問題にはなっていなかっただけでした」
え？何で？何で今回に限ってこれがバリデーション通ってんのよ・・・

難しいことを考えるのはやめましょう。
ただ一つ分かったことは、一意性の検証の場合だけこの「fixture」のデータでテストされているということです。
試しに、これまでのテストてNGとなりそうな値をoneさんとtwoさんの「email」に放り込んでテストしてみました
①one：空白、two：空白
⇨サクセス
②one：aだけをかなりたくさん、two：aだけをたくさん
⇨サクセス
③one：12345、two：12345
⇨NG
このように「空白」「長さ」「フォーマット」などの部分はスルーするのに、同じ文字列という「一意性」にだけ反応している様子が見て取れます。
今の私のスライムベスレベルではなぜなのかは分かりません。
ただ、これをとりあえず解決する方法はシンプルでした

「fixtureの中身を全部消す」

です。悩み考えたのが馬鹿らしくなりましたので、さっさと次に進みましょう

データベース側が規制をスルーしてしまうケースが「一意性」に加えて「大文字小文字の区別」でも、あるみたいです。
これに対処するために**コールバック（callback）メソッド**を使います

**コールバック（callback）メソッド**
ある「特定の」時点で呼び出されるメソッド

今回はこのコールバックメソッドである**「before_save」メソッド**を「データが保存される前」という場面に限定して使用するように配置しましょう（見たまんまな名前ですね）

```app/models/user.rb
class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true
end
```
これで、「email」はバリデーションかける前に強制的に小文字に変換されるようになりました。
検証される「email」のデータが全て小文字になりましたので以下の部分も変更されます

```
uniqueness: { case_sensitive: false } # 大文字と小文字を区別しない！
```
「大文字と小文字を区別しないようにする」という検証は必要なくなりました。

```
uniqueness: true # 単に同じじゃダメ！
```
そういやテストも大文字小文字に対処するようにしていましたね。
必要ないので消しちゃいましょう。

```test/models/user_test.rb
duplicate_user = @user.dup
duplicate_user.email = @user.email.upcase # こいつは消す！
@user.save
assert_not duplicate_user.valid?
```
・・・やっとですが、これでデータベース側にも規制を行ってもらい「落とし穴」を回避することができるようになりました。いや〜「一意性」だけやたら難しいですね。

最後に一応テストしときましょう
サクセスするはずです！！
#6.3 セキュアなパスワードを追加する#
*パスワードの実装について*

６章も終盤戦に差し掛かってきました！
最後は「パスワード」機能を組み込みます。まずはパスワードが必要になる以下の二つの場面で、どのような仕組みで動いているかを簡単に見ていきますと

登録時については・・・ユーザーに登録時パスワードとパスワードの確認をしてもらい、そのデータをハッシュにしてデータベースに保存

ログイン時にユーザー認証する時は・・・パスワードの送信、ハッシュ化、データベース内のハッシュ化された値との比較

など、パスワード機能の実装には「ハッシュ」を多様するみたいですね。
なぜハッシュ化するのかというと、パスワードを暗号化させるためです。そうすればデータベースの内容が漏洩しても（いけませんが）、暗号化して別の形で保存されているため情報として意味をなしておらず、最悪の事態を防ぐことができます。
##6.3.1 ハッシュ化されたパスワード##

兎にも角にもパスワードの実装にはまず第一に**「has_secure_password」というメソッド**をモデルに組み込むことから始まります（その前に下準備が必要ですが）
「has_secure_password」には以下の機能を備えています

- セキュアにハッシュ化したパスワードを、データベース内のpassword_digestという属性に保存できるようになる。
- 2つのペアの仮想的な属性（passwordとpassword_confirmation）が使えるようになる。また、存在性と値が一致するかどうかのバリデーションも追加される
- authenticateメソッドが使えるようになる（引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド）。

へえ〜すごいですね〜。よくわからないけどいろいろできてすごいですね〜〜・・・
ここから最後までこの「has_secure_passoword」の機能や実装方法について見ていきます

1つ目から見ていきましょう
パスワードは「name」や「email」と同様にデータベースに保存されるワケですが、より安全性を高めるためには「そのまま」の形では保存しないようにします。パスワードが漏れちゃったら何でもされちゃいますもんね。
勝手にログインされたり・・購入されたり・・・送金されたり・・・・恐ろしか〜〜

そこで、「has_secure_password」メソッドを使うことによって、データベースにそのまま保存せず、細工して保存するようにするという手を使えるようになります。
そうすれば仮にデータベースが漏洩しても、そこに載ってるパスワードは細工されたものだから、それでは認証通りません。
その細工したパスワードの保存先が**「password_digest」**ということになります。
冒頭からハッシュだのハッシュ化するだの言ってたのは、その「細工する」ということを指していたワケです。
**暗号化**ってよく聞きますよね。あれと同じようなものとしときましょう。

**「has_secure_password」を使用するための2つの前準備**

**①usersテーブルに「password_digest」カラムを追加**
データベースに変更を加える時は・・・・そう！マイグレーションファイルです！
マイグレーションファイルは「rails generate」で作りますよね

```
$ rails generate migration add_password_digest_to_users password_digest:string
```
ここでは「migration」の後に書かれている内容に注目です！
今回のようにカラムを追加したい場合は
「`add_カラム名_to_テーブル名`（add_password_digest_to_users）」の形でrails generateしますと・・・いい感じにマイグレーションファイルが作成されます

```db/migrate/[timestamp]_add_password_digest_to_users.rb
class AddPasswordDigestToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :password_digest, :string
  end
end
```
**`「add_カラム名_to_テーブル名」`**とすることで、データベースに変更を加える「change」メソッドだけでなく、カラムを追加する「add_column」メソッドまで自動で作成されます。

これで、「users」テーブルに「string型」の「password_digest」カラムができま・・・せん！！
危なかったですね〜これを忘れるところでした

```
$ rails db:migrate
```
これで、usersテーブル上に「password_digest」カラムを設置できました

**②パスワードを暗号化する機能を備えた「bcrypt」**
今の段階では暗号化したパスワードの置き場ができただけです。
パスワードのデータを「has_secure_password」を使ってハッシュ化（暗号化）する機能を加えるためには**「bcrypt」というgem**をGemfileに加えるだけでOKみたいです

```Gemfile
gem 'rails',          '6.0.3'
gem 'bcrypt',         '3.1.13' # 今回加えるやつ
gem 'bootstrap-sass', '3.4.1'
```
こんな感じで「bcrypt」を加えときましょう。あとはこれがなんとかしてくれるでしょう
ちなみに「bcrypt」はパスワードを暗号化されたパスワードに変換します。
が、その暗号化されたパスワードを本来のパスワードに変換することは不可能みたいです。

先ほどのマイグレーション同様こちらも忘れずに

```
$ bundle install
```
##6.3.2 ユーザーがセキュアなパスワードを持っている##
先ほどの行った2つの下準備でやっとこさ「has_secure_password」を使える状態になりました。
以下が2つの下準備でした
①password_digestカラムをusersテーブルに追加する
②bcryptをGemfileに追加する

準備ができたので、早速「has_secure_password」をuserモデルに組み込みましょう

```app/models/user.rb
class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true
  has_secure_password # これだけ！！
end
```
これだけです！！1行加えるだけです！！

ここで早速テストしてみましょう。
失敗するんです。最後に一意性のテストをサクセスしてから何もテストを加えていないのに何で失敗するんかね。
犯人は・・・「has_secure_password」ちゃんです！
何と、「password属性」と「password_confirmation属性」に対してバリデーションをする機能を（強制的に）追加しているみたいです。
こんなん分かってないと絶対混乱しますよね。
※実は、先ほど「has_secure_password」の特徴をあげた時、2つ目の特徴として書いていました。。
最初のテスト「"should be valid"」は「このデータは保存するのに有効ですか？」を確認するためのものでしたので、「「password属性」と「password_confirmation属性」が足りてないデータは保存できねーよ」と突き返された形ですね。

「password属性」と「password_confirmation属性」って、パスワード登録する時に毎回書かされる「パスワード」と「確認用パスワード」ってやつですよね
テストでパスするためにはこの2つをテストする前に実行するあのインスタンス変数に入れてやりましょう

```test/models/user_test.rb
def setup
    @user = User.new(name: "Example User", email: "user@example.com", 
                     password: "foobar", password_confirmation: "foobar")
end
```
これで、テスト用のユーザーデータには「名前」「email」「パスワード」「確認用パスワード」の4つが入りました。なんかそれらしくなってきましたね〜〜

データをちゃんと入れたので、今度はテストが通るはずです
しかし、バリデーションを書いたわけでもないのに、勝手に検証されているのって違和感ありますよね。。。
しかもデータとして「password_digest」に保存されるのは暗号化されたパスワードなので強制的に書かされた2つのデータは「保存するのに有効なデータか」を確認されたにも関わらず保存されないという・・・
要は「password属性」と「password_confirmation属性」は保存しなきゃいけないけど、保存されないもの！です

##6.3.3 パスワードの最小文字数##
よくある、「パスワードは〇〇文字以上に設定してください」ってやつです
空白や文字数の制限については、nameやemailでもやりましたね。
実装の手順も同じ、テスト書いてから機能を加える（バリデーションを書く）順番です

```test/models/user_test.rb
  test "password should be present (nonblank)" do
    @user.password = @user.password_confirmation = " " * 6
    assert_not @user.valid?
  end

  test "password should have a minimum length" do
    @user.password = @user.password_confirmation = "a" * 5
    assert_not @user.valid?
  end
```
んんんんん〜〜〜〜！？

```
@user.password = @user.password_confirmation = " " * 6
```
これのことですよね。

```
@user.password = " " * 6
@user.password_confirmation = " " * 6
```
なんてこたありません。この2つに別れいるのを1つにまとめているだけのはなしです。
必ず同じ文字が入るものですから、まとめちゃった方がスッキリしていいですけどね

これで、**「通らない」**テストが完成しました
一応確認しますと「passwordやpassword_confirmationに「空白や5文字」はいかんですよね？」というテストに対し、
「そんなルールねーから！やり直してこい！」といういつもの流れです

「ルールがないなら作ればいい」ということでuserモデルに書いていきまっしょい

```app/models/user.rb
validates :password, presence: true, length: { minimum: 6 }
```
って事で加えた部分だけ書いておきます。
私もさっそく間違えましたが、「length」は<font color="red">「maximum」ではなく「minimum」</font>ですよ！！
パスワードは最大ではなく**最小**6文字です！！

ここでやっとテストが通るようになります。めでたしめでたし。
##6.3.4 ユーザーの作成と認証##

この節では、実際にデータベースに新規ユーザーを1人作成して「has_secure_password」を導入したあとのパスワードの行方を追っていきます。
これまでは「rails console --sandbox」を使って、データベースにデータを残さないようにしましたが、今回はデータを残したいので「rails console」で作業しましょう

```
$ rails console # サンドボックスは使いません
>> User.create(name: "Michael Hartl", email: "michael@example.com",password: "foobar", password_confirmation: "foobar")
```
「User.create」を使って一気に保存までやってますな
そういやデータベースにはpasswordもpassword_confirmationも作ってなくて、作ったのは暗号化されたパスワードが入る「password_digest」でっした
これがどんな風に保存されているか見ることができます

```
>> user = User.find_by(email: "michael@example.com") # まずは変数に代入
>> user.password_digest
=> "$2a$12$WgjER5ovLFjC2hmCItmbTe6nAXzT3bO66GiAQ83Ev03eVp32zyNYG"
```
おおおお。勝手にハッシュ化されて、それがちゃんと「password_digest」に保存されていますね。

また、今さらですが「has_secure_password」の3つ目の特徴を回収します
『authenticateメソッドが使えるようになる（引数の文字列がパスワードと一致するとUserオブジェクトを、間違っているとfalseを返すメソッド）。』てやつですね。

**authenticateメソッドとは**
「パスワードを暗号化した値」と「password_digestに保存された値」を比較して、同じものであるかどうかを判断してくれます。

よくよく考えるとこれがないと、大変困りますよね。
上の例で見てみると、Michaelさんはパスワードを"foobar"と保存したはずなのに、データベース上では`"$2a$12$WgjER5ovLFjC2hmCItmbTe6nAXzT3bO66GiAQ83Ev03eVp32zyNYG"`として保存されています。
別の値として見られてしまうと、Michaelさんはログインする時にパスワードに「foobar」と入力したところで弾かれてしまいます。

この「authenticate」メソッドについては8章で掘り下げていくみたいですので、ここはこの辺りで逃げ出しときます・・・アディオス！！
#6.4 最後に#
いつものようにブランチに変更をマージしたり、Gitにプッシュしたり、Herokuにデプロイしましょう

```
$ git add -A
$ git commit -m "Finish layout and routes"
$ git checkout master
$ git merge filling-in-layout
```
Gitにpushする前にテストをするのを忘れずに

```
$ rails test
$ git push
```
最後にHerokuへデプロイです

```
$ git push heroku
```
#6章の要約をようやく作り終えての感想#
今回特に感じたのは、バリデーションやテストはコピペするよりも、自分で書いた方が頭に入りやすい印象があるなということです。
1周目（丸写しだけ）した時は何も見てなかったなと思います。1行1行和訳してると本当に時間がかかって仕方ありません。。。まだまだ先は長いですが、「集中してやる」これに尽きます。。。