②Elixirユーザ認証ライブラリ「phx_gen_auth」の本番向け改造点：バリデーションのカスタマイズ

[Elixir Digitalization Implementors／fukuoka.ex／kokura.ex](https://fukuokaex.connpass.com/)のpiacereです
ご覧いただいて、ありがとうございます :bow:

[前回](https://qiita.com/piacerex/items/35dc7ee8129b9a1deb9d)に引き続き、Phoenixユーザ認証ライブラリ「phx_gen_auth」のプロダクション向け改造ポイントとして、今回は、バリデーションのカスタマイズについて解説します

<h3>:ocean::ocean: Elixir ranked second on the Qiita Advent calendar :ocean::ocean:</h3>

In the programming language category ranking, Rust was 1st, Elixir was 2nd, Golang was 3rd, and all were modern programming languages.:laughing:
https://qiita.com/advent-calendar/2020/elixir
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/ea185203-c525-c778-dc10-6d2ecc391616.png)](https://qiita.com/advent-calendar/2020/elixir)

In addition, our Elixir community "fukuoka.ex" has won the top spot in the Web Technology category.
https://qiita.com/advent-calendar/2020/fukuokaex
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/8a22a81f-2917-6072-10bd-525e0fc24b75.png)](https://qiita.com/advent-calendar/2020/neosvr_reso)

# 本コラムの検証環境

本コラムは、以下環境で検証しています（Windowsで実施していますが、Linuxやmacでも動作する想定です）

- Windows 11
- Elixir 1.12.0 on WSL2 Ubuntu　※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacerex/items/6b64dfe70f48c89d8385)</b>
- Phoenix 1.6.0　　　　　　　　※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/b7787580fce5f148242f#phoenix%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>
- PostgreSQL 10.17　　　　　　※<b>[最新版のインストール手順はコチラ](https://qiita.com/piacere_ex/items/a7558adc6856e3577dc6#postgresql%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)</b>

なお、本コラム内で扱うPhoenix PJ名は「basic」、phx_gen_authのコンテキスト名は「Accounts」を前提にしています

# ②バリデーションのカスタマイズ

## ②－１：バリデーションメッセージの日本語化

バリデーションが実装されている下記をカスタマイズします

なお、ページ上部に出るエラーメッセージは、後続のシリーズで解説し、ここでは各項目のバリデーションメッセージの修正のみとなります

各バリデーション関数の利用場所（「lib/basic/accounts/account.ex」内）、バリデーション内容は、下記表の通りです（なお、PWはパスワードの略）

関数名 | 利用場所 | バリデーション内容
-|-|-
validate_email | ユーザ登録（/accounts/registration）<br>情報変更 [メアド変更]（/accounts/settings） | メールアドレスの<br>必須チェック
validate_email | ユーザ登録<br>情報変更 [メアド変更] | 登録済みメールアドレス<br>との一致チェック
validate_password | ユーザ登録<br>PWリセット実施（/accounts/reset_password）<br>情報変更 [PW変更]（/accounts/settings） | PW必須チェック
validate_password | ユーザ登録<br>情報変更 [PW変更] | PW長さチェック
validate_password | ユーザ登録<br>情報変更 [PW変更] | PW文字種チェック<br>（コメントアウト済）
email_changeset | 情報変更 [メアド変更] | 登録済みメールアドレス<br>との一致チェック
password_changeset | 情報変更 [PW変更] | PWとPW確認の<br>入力一致チェック
validate_current_password | 情報変更 [メアド変更、PW変更] | 登録済みPW<br>との一致チェック

バリデーションメッセージの日本語化は、以下の通りです

デフォルトではコメントアウトされている英小文字／英大文字／記号を含めるチェックは、利用時だけ文言変更を行ってください

```diff_elixir:lib/basic/accounts/account.ex
defmodule Basic.Accounts.Account do
…
  defp validate_email(changeset) do
    changeset
-   |> validate_required([:email])
+   |> validate_required([:email], message: "必須項目ですのでご入力ください")
-   |> validate_format(:email, ~r/^[^\s]+@[^\s]+$/, message: "must have the @ sign and no spaces")
+   |> validate_format(:email, ~r/^[^\s]+@[^\s]+$/, message: "「@」がありません、もしくは半角スペースは使えません")
    |> validate_length(:email, max: 160)
-   |> unsafe_validate_unique(:email, Basic.Repo)
+   |> unsafe_validate_unique(:email, Basic.Repo, message: "すでに登録済みです")
    |> unique_constraint(:email)
  end
…
  defp validate_password(changeset, opts) do
    changeset
-   |> validate_required([:password])
+   |> validate_required([:password], message: "必須項目ですのでご入力ください")
-   |> validate_length(:password, min: 12, max: 72)
+   |> validate_length(:password, min: 12, message: "%{count}文字以上にしてください")
+   |> validate_length(:password, max: 72, message: "%{count}文字以内にしてください")
    # Examples of additional password validation:
-   # |> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character")
+   # |> validate_format(:password, ~r/[a-z]/, message: "英小文字を含めてください")
-   # |> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character")
+   # |> validate_format(:password, ~r/[A-Z]/, message: "英大文字を含めてください")
-   # |> validate_format(:password, ~r/[!?@#$%^&*_0-9]/, message: "at least one digit or punctuation character")
+   # |> validate_format(:password, ~r/[!?@#$%^&*_0-9]/, message: "記号文字を含めてください")
    |> maybe_hash_password(opts)
  end
…
  def email_changeset(account, attrs) do
    account
    |> cast(attrs, [:email])
    |> validate_email()
    |> case do
      %{changes: %{email: _}} = changeset -> changeset
-     %{} = changeset -> add_error(changeset, :email, "did not change")
+     %{} = changeset -> add_error(changeset, :email, "変更ができません")
    end
  end
…
  def password_changeset(account, attrs, opts \\ []) do
    account
    |> cast(attrs, [:password])
-   |> validate_confirmation(:password, message: "does not match password")
+   |> validate_confirmation(:password, message: "パスワードが一致しません")
    |> validate_password(opts)
  end
…
  def validate_current_password(changeset, password) do
    if valid_password?(changeset.data, password) do
      changeset
    else
-     add_error(changeset, :current_password, "is not valid")
+     add_error(changeset, :current_password, "正しくありません")
    end
  end
…
```

## ②－２：バリデーションのカスタマイズ

たとえば、phx_gen_authのデフォルトは、パスワード長チェックが12文字以上80文字以内と、やたら長いので、下記のように、8文字以上16文字以内といった、適当な長さに変更できます

英小文字／英大文字／記号を含めるチェックもデフォルトで入っているので、必要に応じて解除してください

```diff_elixir:lib/basic/accounts/account.ex
defmodule Basic.Accounts.Account do
…
  defp validate_password(changeset, opts) do
    changeset
    |> validate_required([:password])
-   |> validate_length(:password, min: 12, max: 80)
+   |> validate_length(:password, min: 8, message: "%{count}文字以上にしてください")
+   |> validate_length(:password, max: 16, message: "%{count}文字以内にしてください")
    |> validate_length(:password, min: 12, max: 72)
    # Examples of additional password validation:
    # |> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character")
    # |> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character")
    # |> validate_format(:password, ~r/[!?@#$%^&*_0-9]/, message: "at least one digit or punctuation character")
    |> maybe_hash_password(opts)
  end
…
```

その配下にある、元からコメントアウトされた行を解除すると下記のバリデーションが有効になります

下記は、PWに英字小文字を最低1文字は記入することを強制します

```elixir
    |> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character")
```

下記は、PWに英字大文字を最低1文字は記入することを強制します

```elixir
    |> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character")
```

下記は、PWに数字もしくは特殊文字（!、?、@、#、$、%、^、&、*、_）を最低1文字は記入することを強制します

```elixir
    |> validate_format(:password, ~r/[!?@#$%^&*_0-9]/, message: "at least one digit or punctuation character")
```

このように、validate_formatを使えば、任意の正規表現でバリデーションを追加することができます

``validate_email`` に同様のvalidate_formatを追加すれば、メールアドレスに任意の正規表現でバリデーションを追加することもできます

他に利用可能な汎用バリデーションは、下記コラムをご参考ください

https://qiita.com/su_mi/items/feb97e62aa24c73b3eb0

https://qiita.com/tuchiro/items/de56e38efa8c397abdff#user%E3%82%B9%E3%82%AD%E3%83%BC%E3%83%9E%E3%81%AE%E4%BF%AE%E6%AD%A3

https://elixirschool.com/ja/lessons/ecto/changesets/#%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3

https://hexdocs.pm/ecto/Ecto.Changeset.html

# 最後に

今回は、ユーザ認証ライブラリ「phx_gen_auth」のプロダクション向け改造ポイントのうち、バリデーションについて解説しました

phx_gen_authのバリデーションは、最初から割としっかり作り込まれていますが、日本語化と、細かいカスタマイズは、本コラムを参考にトライしてみてください

[次回は、ページヘッダーの調整](https://qiita.com/piacerex/items/58c878efd81920c8aa22)をします