Rails チュートリアル 第6章 備忘録

第6章の備忘録

##環境
Rails 6.0.3
Ruby 2.6.3

##目次
[1 rails console --sandbox](#1-rails-console---sandbox)
[2 new と update メソッドの違い](#2-new-と-update-メソッドの違い)
[3 検証 Validation](#3-検証-validation)
[4 セキュアなパスワード](#4-セキュアなパスワード)

###1 rails console --sandbox
`rails console`と違って、終了時にrolbackされるのが特徴！
データベースを変更せずに色々試したい場合はこちらを使う。


###2 new と update メソッドの違い
####newメソッド
saveメソッドと併用して、データベースに保存する。

####updateメソッド
updateメソッドは成功時に更新と保存を一括で行う。
ただし、1つでも失敗するとupdateメソッド自体が失敗する。
もし、特定の値のみupdateしたい場合は**update_attribute**メソッドを使う。

```
>> user.update_attribute(:name, "testName")
=> true
>> user.name
=> "testName"
```


###3 検証 Validation

####存在性 :presence
渡された属性が存在することを検証
（例）**presence: true**

####長さ :length
email等の長さに制限を設ける
（例）**length: { maximum: 50 }**

####フォーマット　:format
適切なemailの形式になっているか等を確認することを要求できる
特にemailのフォーマットを設定する時には**正規表現**を用いる。
使いたい時に調べればいいかな〜って感じ。覚えておくのは難しい💦何回か実際に使えば自然に覚えるかな〜ぐらいのスタンス。。
（例）**format: { with: ~~~ }**

####一意性 :uniqueness
重複しないことを設定することができる
またRailsチュートリアルでは、ユーザーが新規登録する時に誤ってボタンを素早く2回押してしまうことでリクエストが2回送られた時に、一意性が保たれるよう、データベースレベルでも`email`のカラムにインデックスを追加している。
（例）**uniqueness: true**

```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
```

**最後にパスワードも含めたバリデーションをテストコード含め掲載してます**

####errors.messages メソッド
バリデーションを行っている時にエラーが出たら、errors.messages(errors.full_messages)メソッドを使うことで、エラーの内容が確認できる。便利！

```
>> # 例
>> user.errors.full_messages
=> ["Name can't be blank"]
```

###4 セキュアなパスワード

セキュアパスワードの手法は、ユーザーにパスワードともう一度パスワードの確認を行い、ハッシュ化したものをデータベースに保存する。
ここでの**ハッシュ化**とは、**ハッシュ関数を使って、パスワードを元に戻すことができないデータに変換する処理**のことである。

セキュアなパスワードの実装はまず、`has_secure_password`メソッドをModelで呼び出す。

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

has_secure_passwordメソッドの機能を使えるようにするための条件は、モデル内に`password_digest`属性が含まれていること。ここにハッシュ化されたパスワードが保存される。

また`has_secure_password`メソッドを使ってハッシュ化するには`bcrypt`gemを追加する必要がある。


最後に、テストコードを抜粋して、学びになった部分を掲載
2周目になると、テストコードの流れがしっかり理解できる！！


```app/models/user.rb
class User < ApplicationRecord
  # 保存前にemailを全て小文字に書き換え
  before_save { email.downcase! }
  
  validates :name, presence: true, length: { maximum: 50 }
  
  # emailの正規表現を定数で用意
  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
  validates :password, presence: true, length: { minimum: 6 }
end
```

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

class UserTest < ActiveSupport::TestCase
  def setup
    @user = User.new(name: "Example User", email: "user@example.com",
          password: "foobar", password_confirmation: "foobar")
  end

# 抜粋して取り上げる

  # 誤ったemailが適切に拒否されるかチェック
  test "email validation should reject invalid addresses" do
    # invalidなemailをいくつか配列にまとめる。%wを使用。空白で分ける
    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
      # valid? : その値が妥当かチェック。assert_notと併用して、妥当でないことが適切に判定されるかチェック
      # 第2引数に、エラーが分かるように文字列を設定
      assert_not @user.valid?, "#{invalid_addresses} should be invalid"
    end
  end

  test "email addresses should be unique" do
    # dupメソッド : 複製する
    duplicate_user = @user.dup
    @user.save
    # 同じemailが適切に拒否されるかチェック
    assert_not duplicate_user.valid?
  end

  test "password should be present (noneblank)" do
    @user.password = @user.password_confirmation = " " * 6
    assert_not @user.valid?
  end

end
```