アプリを作る　ユーザーのモデルを作成する

###Userモデルを生成する
```rb
ubuntu:~/environment/my_app (modeling-users) $ rails generate model User name:string email:string
Running via Spring preloader in process 3689
      invoke  active_record
      create    db/migrate/*********_create_users.rb
      # 　Usersテーブルの詳細を設定させるファイル
      create    app/models/user.rb
      # useデータモデルの使用を書く
      invoke    test_unit
      create      test/models/user_test.rb
      # そのテストファイル
      create      test/fixtures/users.yml
      # テストユーザーのファイル
```

###（usersテーブルを作るための）Userモデルのマイグレーション
マイグレーションは元のシステムからデータなどを抽出して移行させる

db/migrate/[timestamp]_create_users.rb

```rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
  # userのデータモデルのカラムを設定させる
    create_table :users do |t|
    # create_table テーブルを作成 
    # usersというテーブルから要素を一つずつ取り出す
      t.string :name
      # nameカラムを生成　属性 文字列
      t.string :email
      # emailカラムを生成　属性 文字列
      t.timestamps
      # created_atとupdated_atを作成 
      # 多分日付が代入させる
    end
  end
end
```
###有効なUserかどうかをテストする
test/models/user_test.rb

```rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
    # テストユーザー
    # create_user.rbでusersテーブルに沿って作成
    # 現時点では有効
  end

  test "should be valid" do
    assert @user.valid?
    # usersテーブルで有効なデータモデルか確認
  end

  test "name should be present" do
    @user.name = "     "
    # 名前を空にする
    assert_not @user.valid?
    # 空にしたデータテーブルは無効か？
  end
end
```
　

```
ubuntu:~/environment/my_app (modeling-users) $ rails test:models
Run options: --seed 28244

Running:

F

Failure:
UserTest#test_name_should_be_present [/home/ubuntu/environment/my_app/test/models/user_test.rb:20]:
Expected true to be nil or false


rails test test/models/user_test.rb:17

.

Finished in 0.031667s, 63.1576 runs/s, 63.1576 assertions/s.
2 runs, 2 assertions, 1 failures, 0 errors, 0 skips
```
nilかfalseが返ってくるからどうかしてほしいらしい。

なので
渡された属性が存在することを検証します。「存在性（Presence）を調べる。のか？

name属性の存在性を検証する
app/models/user.rb

```rb
class User < ApplicationRecord
# 継承させる
  validates :name, presence: true
  # nameカラムが存在する
  # validates(:name, presence: true)と書くこともできる
end
```
存在性（presence）の検証、長さ（length）の検証、フォーマット（format）の検証、一意性（uniqueness）の検証です。6.3.2では、よく使われる最終検証として確認（confirmation）を追加します。

###ユーザー側の入力する名前とメアドの仕様
user.rb

```rb
class User < ApplicationRecord
# 継承させる
  validates :name, presence: true, length: { maximum: 50 }
  # nameカラムが存在する
  # validates(:name, presence: true)
  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: { case_sensitive: false } 
                    # :case_sensitive	大文字と小文字を区別しないで一意性を検証する
end
```

###ユーザー側の入力された名前とメアドのテスト
test/models/user_test.rb

```rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
    # テストユーザー
    # create_user.rbでusersテーブルに沿って作成
    # 現時点では有効
  end

  test "should be valid" do
  # 有効を検証
    assert @user.valid?
    # usersテーブルで有効なデータモデルか確認
  end
  
  test "name should be present" do
    @user.name = ""
    # 名前を空にする
    assert_not @user.valid?
    # 空にしたデータテーブルは無効か？
  end
  
  test "email should be present" do
  # 存在性の検証
    @user.email = "     "
    # メールを空にする
    assert_not @user.valid?
    # 無効か？
  end
  
  test "name should not be too long" do
  # 長さの検証
    @user.name = "a" * 51
    # 文字列の長さを検証
    assert_not @user.valid?
    # 無効か？
  end

  test "email should not be too long" do
    @user.email = "a" * 244 + "@example.com"
    # 文字列の長さの検証
    assert_not @user.valid?
    # 無効か？
  end
  
   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"
      # ドメイン名は有効か？
      # "#{valid_address.inspect} should be valid" エラ〜メッセージ
    end
  end
  
  test "email validation should reject invalid addresses" do
    invalid_addresses = %w[user@example,com user_at_foo.org user.name@example.
                           foo@bar_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
  
  test "email addresses should be unique" do
  # 一意性の検証
    duplicate_user = @user.dup
    # dup オブジェクトのコピーを作成するメソッド
    # 同じものを作って比較する
    duplicate_user.email = @user.email.upcase
    # 大文字のアドレスに上書き
    @user.save
    assert_not duplicate_user.valid?
    # 無効か？
  end
end
```
これだけでは正常にデータベース上に保存できない可能性があるので、
データベース上でも一意性を持たせるようにする

```rb
ubuntu:~/environment/my_app (modeling-users) $ rails generate migration add_index_to_users_email
Running via Spring preloader in process 9987
      invoke  active_record
      create    db/migrate/20211115141312_add_index_to_users_email.rb
      # このファイルでデータベース上の一意性を担保させる
```
###メールアドレスの一意性を強制するためのマイグレーション
db/migrate/[timestamp]_add_index_to_users_email.rb

```rb
class AddIndexToUsersEmail < ActiveRecord::Migration[6.0]
  def change
  # データベースの一意性を保つ
    add_index :users, :email, unique: true
    # add_index 指定したテーブルにインデックスを追加
    # usersデータモデルのemailカラムを追加 一意性もつける
    # 一度データベースに保存されたら同じのは保存できない
  end
end
```
```
$ rails db:migrate
```
```rb
ubuntu:~/environment/my_app (modeling-users) $ rails generate migration add_password_digest_to_users password_digest:string
Running via Spring preloader in process 11571
      invoke  active_record
      create    db/migrate/20211115142724_add_password_digest_to_users.rb
```
###password_digestカラムを追加するマイグレーション
db/migrate/[timestamp]_add_password_digest_to_users.rb

```rb
class AddPasswordDigestToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :password_digest, :string
    # usersテーブルのpassword_digesetカラムを追加 属性は文字列
  end
end
```
```
$rails db:migrate
```

###gemfile
```
gem  'rails' ....
gem 'bcrypt',         '3.1.13'
```

```rb
class User < ApplicationRecord
# 継承させる
  before_save { self.email = email.downcase }
  # 保存する前に　メアドは小文字にする
  validates :name, presence: true, length: { maximum: 50 }
  # nameカラムが存在する
  # validates(:name, presence: true)
  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: { case_sensitive: false } 
                    # :case_sensitive	大文字と小文字を区別しないで一意性を検証する
  has_secure_password
  # 仮想的なpassword属性とpassword_confirmation属性に対してバリデーションをする機能も（強制的に）追加
end
```
selfは省略形
セキュアなパスワーを実装するために

```
has_secure_password
```
と書くらしい。

```rb
class AddIndexToUsersEmail < ActiveRecord::Migration[6.0]
  def change
  # データベースの一意性を保つ
    add_index :users, :email, unique: true
    # add_index 指定したテーブルにインデックスを追加
    # usersデータモデルのemailカラムを追加 一意性もつける
    # 一度データベースに保存されたら同じのは保存できない
  end
end
```
データベースのカラムの追加をしたら

```
rails db:migrate
```
を行うらしい。

password_digestも追加する

```rb
class AddPasswordDigestToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :password_digest, :string
    # usersテーブルのpassword_digesetカラムを追加 属性は文字列
  end
end
```

###パスワードの最小文字数を設定
その前にテストを作成し、どう動いてほしいかをかく。

```rb: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
end
```
空白と五文字以下の場合はパスワードととして認定しないようにしたい。
なので

```rb:app/models/user.rb
.
.
.
  has_secure_password
  # 仮想的なpassword属性とpassword_confirmation属性に対してバリデーションをする機能も（強制的に）追加
  validates :password, presence: true, length: { minimum: 6 }
  # 最低でも六文字異常 存在性のある文字列をパスワードととする。
  # 渡された属性が存在していることを検証する
end
```
これでパスワードの様式を設定できた。