[Rails]パスワードのバリデーションに正規表現を使用してみた[format]

#はじめに
今回は、正規表現でパスワードのバリデーションをしてみました。
railsではformatというバリデーションヘルパーで正規表現を使用することができます。
求めるパスワードの条件として「半角6~12文字で英大文字・英小文字・数字それぞれ１文字以上含む」でないと登録できないようにしました。
実行結果はRSpecのモデルのテストで確認していきます。

###参考にさせていただいた記事等
[言語別：パスワード向けの正規表現](https://qiita.com/mpyw/items/886218e7b418dfed254b)
[パスワード向け正規表現 /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i を解読する](https://qiita.com/momotaro98/items/460c6cac14473765ec14)

###前提条件
すでにユーザー作成機能作成を作成済みとします。
私はrailsチュートリアルで作成したログイン機能を使って進めました。
完成したもの先に記載するしておきます。

```ruby:/app/model/user.rb
VALID_PASSWORD_REGEX =/\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[\d])\w{6,12}\z/
  validates :password, presence: true,
            format: { with: VALID_PASSWORD_REGEX,
             message: "は半角6~12文字英大文字・小文字・数字それぞれ１文字以上含む必要があります"}
```


#1.テストを失敗させる
失敗するテストを書く前に現状のpasswordに関するバリデーションを確認します。
現状ではパスワードが空でないこと、長さが６文字以上であることのみのバリデーションとなってます。

```ruby/app/model/user.rb
validates :password, presence: true, length: { minimum: 6 }
```

失敗するテストはこちら。

```ruby:spec/mpdel/user_spec.rb
  it 'パスワードに英小文字が含まれない場合無効な状態であること' do
    user = User.new(password: '1'+'A' * 5, password_confirmation: '1A'+'a' * 3)
    user.valid?
    expect(user.errors[:password]).to include('は半角6~12文字英大文字・小文字・数字それぞれ１文字以上含む必要があります')
  end

  it 'パスワードに英大文字が含まれない場合無効な状態であること' do
    user = User.new(password: '1'+'a' * 5, password_confirmation: '1A'+'a' * 3)
    user.valid?
    expect(user.errors[:password]).to include('は半角6~12文字英大文字・小文字・数字それぞれ１文字以上含む必要があります')
  end

  it 'パスワードに数字が含まれない場合無効な状態であること' do
    user = User.new(password: 'A'+'a' * 5, password_confirmation: '1A'+'a' * 3)
    user.valid?
    expect(user.errors[:password]).to include('は半角6~12文字英大文字・小文字・数字それぞれ１文字以上含む必要があります')
  end

  it 'パスワードが5文字以下なら無効な状態であること' do
    user = User.new(password: '1A'+'a' * 3, password_confirmation: '1A'+'a' * 3)
    user.valid?
    expect(user.errors[:password]).to include('は半角6~12文字英大文字・小文字・数字それぞれ１文字以上含む必要があります')
  end

  it 'パスワードが13文字以上なら無効な状態であること' do
    user = User.new(password: '1A'+'a' * 11, password_confirmation: '1A'+'a' * 11)
    user.valid?
    expect(user.errors[:password]).to include('は半角6~12文字英大文字・小文字・数字それぞれ１文字以上含む必要があります')
  end

```
テストをしますが失敗します。

```
rspec spec/models/user_spec.rb

User
  パスワードに英小文字が含まれない場合無効な状態であること (FAILED - 1)
  パスワードに英大文字が含まれない場合無効な状態であること (FAILED - 2)
  パスワードに数字が含まれない場合無効な状態であること (FAILED - 3)
  パスワードが5文字以下なら無効な状態であること (FAILED - 4)
  パスワードが13文字以上なら無効な状態であること (FAILED - 5)

5 examples, 5 failures
```

#2.コードを修正する

```ruby:/app/model/user.rb
VALID_PASSWORD_REGEX =/\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[\d])\w{6,12}\z/
  validates :password, presence: true,
            format: { with: VALID_PASSWORD_REGEX,
             message: "は半角6~12文字英大文字・小文字・数字それぞれ１文字以上含む必要があります"}
```
VALID_PASSWORD_REGEXにformatのwithオプションに指定する正規表現をセットします。formatではwithオプションの正規表現と属性（パスワード）がマッチするか検証します。messageには失敗したときのカスタムエラーメッセージを設定できます。（railsを日本語化していないとエラーになると思いますので日本語を使う際は注意してください。）

これでテストします。（ユーザーが有効な状態であることも確認するテストも追加）

```ruby:spec/mpdel/user_spec.rb
it '名前、メール、パスワードがあれば有効な状態であること' do
    user = User.new(
      name: 'Aaron',
      email: 'tster@example.com',
      password: 'foobar12A',
      password_confirmation: 'foobar12A'
    )
    expect(user).to be_valid
  end
  
以下略
```

```
rspec spec/models/user_spec.rb
名前、メール、パスワードがあれば有効な状態であること
  パスワードに英小文字が含まれない場合無効な状態であること
  パスワードに英大文字が含まれない場合無効な状態であること
  パスワードに数字が含まれない場合無効な状態であること
  パスワードが5文字以下なら無効な状態であること
  パスワードが13文字以上なら無効な状態であること

Finished in 0.38981 seconds (files took 3.59 seconds to load)
6 examples, 0 failures
```
これで期待するパスワードのバリデーションを追加することができました！