Elixir Digitalization Implementors/fukuoka.ex/kokura.exのpiacereです
ご覧いただいて、ありがとうございます
前回に引き続き、Phoenixユーザ認証ライブラリ「phx_gen_auth」のプロダクション向け改造ポイントとして、今回は、バリデーションのカスタマイズについて解説します

Elixir ranked second on the Qiita Advent calendar 
In the programming language category ranking, Rust was 1st, Elixir was 2nd, Golang was 3rd, and all were modern programming languages.
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
本コラムの検証環境
本コラムは、以下環境で検証しています(Windowsで実施していますが、Linuxやmacでも動作する想定です)
- Windows 11
- Elixir 1.12.0 on WSL2 Ubuntu ※最新版のインストール手順はコチラ
- Phoenix 1.6.0 ※最新版のインストール手順はコチラ
- PostgreSQL 10.17 ※最新版のインストール手順はコチラ
なお、本コラム内で扱うPhoenix PJ名は「basic」、phx_gen_authのコンテキスト名は「Accounts」を前提にしています
②バリデーションのカスタマイズ
②-1:バリデーションメッセージの日本語化
バリデーションが実装されている下記をカスタマイズします
なお、ページ上部に出るエラーメッセージは、後続のシリーズで解説し、ここでは各項目のバリデーションメッセージの修正のみとなります
各バリデーション関数の利用場所(「lib/basic/accounts/account.ex」内)、バリデーション内容は、下記表の通りです(なお、PWはパスワードの略)
関数名 | 利用場所 | バリデーション内容 |
---|---|---|
validate_email | ユーザ登録(/accounts/registration) 情報変更 [メアド変更](/accounts/settings) |
メールアドレスの 必須チェック |
validate_email | ユーザ登録 情報変更 [メアド変更] |
登録済みメールアドレス との一致チェック |
validate_password | ユーザ登録 PWリセット実施(/accounts/reset_password) 情報変更 [PW変更](/accounts/settings) |
PW必須チェック |
validate_password | ユーザ登録 情報変更 [PW変更] |
PW長さチェック |
validate_password | ユーザ登録 情報変更 [PW変更] |
PW文字種チェック (コメントアウト済) |
email_changeset | 情報変更 [メアド変更] | 登録済みメールアドレス との一致チェック |
password_changeset | 情報変更 [PW変更] | PWとPW確認の 入力一致チェック |
validate_current_password | 情報変更 [メアド変更、PW変更] | 登録済みPW との一致チェック |
バリデーションメッセージの日本語化は、以下の通りです
デフォルトではコメントアウトされている英小文字/英大文字/記号を含めるチェックは、利用時だけ文言変更を行ってください
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
…
②-2:バリデーションのカスタマイズ
たとえば、phx_gen_authのデフォルトは、パスワード長チェックが12文字以上80文字以内と、やたら長いので、下記のように、8文字以上16文字以内といった、適当な長さに変更できます
英小文字/英大文字/記号を含めるチェックもデフォルトで入っているので、必要に応じて解除してください
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文字は記入することを強制します
|> validate_format(:password, ~r/[a-z]/, message: "at least one lower case character")
下記は、PWに英字大文字を最低1文字は記入することを強制します
|> validate_format(:password, ~r/[A-Z]/, message: "at least one upper case character")
下記は、PWに数字もしくは特殊文字(!、?、@、#、$、%、^、&、*、_)を最低1文字は記入することを強制します
|> validate_format(:password, ~r/[!?@#$%^&*_0-9]/, message: "at least one digit or punctuation character")
このように、validate_formatを使えば、任意の正規表現でバリデーションを追加することができます
validate_email
に同様のvalidate_formatを追加すれば、メールアドレスに任意の正規表現でバリデーションを追加することもできます
他に利用可能な汎用バリデーションは、下記コラムをご参考ください
最後に
今回は、ユーザ認証ライブラリ「phx_gen_auth」のプロダクション向け改造ポイントのうち、バリデーションについて解説しました
phx_gen_authのバリデーションは、最初から割としっかり作り込まれていますが、日本語化と、細かいカスタマイズは、本コラムを参考にトライしてみてください
次回は、ページヘッダーの調整をします