この記事は、fukuoka.ex Elixir/Phoenix Advent Calendar 2020 14日目です。
前日は、 @piacerex さんの [書評] プログラミングElixir第2版のインプレッションとアップデート でした
Elixirでバリデーションを実装してみた
@tuchiro さんのこちらの記事の手順に沿って進めました。
DBラッパーEctoのchangesetでお手軽入力チェック
https://qiita.com/tuchiro/items/de56e38efa8c397abdff
(※環境構築のみ元記事のPhoenix 1.3から現行最新版のPhoenix 1.5に変更、以降は記事通りの手順です)
実装の概要
- PhoenixのSSR(Server Side Rendering)であるEExでユーザー登録を行うWebアプリを実装する。
- Webアプリは、PhoenixのWeb CRUD自動生成コマンドで構築する
- DBはデフォルトのPostgreSQLを選択する。
- Ecto.Changesetで入力チェックを行う。
バリデーション仕様は以下の通り
- 必須項目チェックの内容をカスタマイズする
- パスワードの桁範囲、許容文字チェックを行う(パスワードのハッシュ化については別の記事が参考になるので割愛)
- 電話番号が全角入力されたら自動的に半角変換する
- emailアドレスが正しい書式かフォーマットをチェックする
- コード値項目は事前に定義したメンバーと一致するか妥当性チェックを行う。
- メールアドレスを業務的なユニークキーとして、重複チェックを行う。
完成したもの
以下コマンドで環境構築後、元記事の「depsにMojiexを追加」以降をそのまま進めると、バリデーションがかかるようになりました。
$mix phx.new ecto_changeset_sample
$cd ecto_changeset_sample
$mix ecto.create
下記の通り、不正な値を入力して、SAVEボタンを押下すると、バリデーションエラーが表示されます。
実装箇所(changesetの内容)
lib/ecto_changeset_sample/accounts/user.exをカスタマイズ
@doc false
def changeset(user, attrs) do
user
|> cast(attrs, [:name, :age, :email, :password, :phone_number, :grade, :resident_type])
|> validate_required([:name, :age, :email, :password, :grade])
|> validate_length(:password, min: 8, max: 16)
|> validate_format(:password, ~r/\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]/)
|> validate_confirmation(:password, message: "does not match password")
|> put_change(:phone_number, Mojiex.convert(attrs["phone_number"],{:ze,:he}))
|> validate_length(:phone_number, min: 10, max: 11)
|> validate_format(:phone_number, ~r/[0-9]{10,11}/)
|> validate_format(:email, ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)
|> validate_inclusion(:grade, Map.values(grade()))
|> validate_inclusion(:resident_type, Map.values(resident_type()))
|> unique_constraint(:email)
end
end
- validate_required は必須チェック(全項目必須適用になっている)
- validate_length で文字長の範囲チェック
- validate_format で正規表現チェック
- validate_confirmation で確認入力チェック(主にパスワード用)
- put_change を使えば、半角全角大文字小文字など文字揺らぎの自動変換も可能
- validate_inclusion で選択肢の妥当性チェック(数字の範囲などもチェック可能)
(tuchiroさんの記事より抜粋)
バリデーションは実装できましたが、大元のchangesetについては、
時間が足りず調べられなかった為、次の記事を読んで学びたいと思います。
elixirschool チェンジセット
https://elixirschool.com/ja/lessons/ecto/changesets/
手順以外で実施したこと
PostgreSQLインストール
How to Install and Configure PostgreSQL Server on macOS Mac OS X
↑↑こちらの動画は @piacerex さんにご紹介頂きました。
説明が丁寧でわかりやすく、導入後も使いやすいと思いました。
Phoenix起動時、cryptoライブラリロードエラーが出た
次のエラーが表示されました。
(エラーは、下記の @takasehideki さんの記事と同じものです。)
macOS CatalinaでErlang 22.2がビルドできない時の対処法
【対処方法】 以下のElixir/Erlangバージョンに上げた
- Elixir-1.11.2
- Erlang-23.1.5
【ポイント】
エラーの原因は、環境の差異、Elixir/Erlangのバージョンが古い為によるもので、
数年前の記事などを参考にする場合は、新しいバージョンに更新した方が良いようです。
asdfでerlang install,brew update失敗など、色々あり・・・
asdfをアンインストールして、brew自体を入れ直してなんとかなりました。
asdfのアンインストール手順はこちら
Homebrewのアンインストール手順はこちら
Phoenixのアンインストール/インストールの手順はこちら
Node.jsインストール
- Node.jsインストール
nodejs.orgのサイトより - cd assets
- npm install
Ecto.Repoのコンパイルでエラーが出た
次のエラーが表示されました。
【対処方法】 下記コマンドを実行
$export MIX_ENV=dev
$mix deps.get
$mix ecto create
【ポイント】
エラーの原因は、Ectoアダプターの設定が無いとのことで、Elixir PJの起動環境が、
以前実施したProdのままになっていたようなので、devに戻しました。
DB接続エラーが出た
次のエラーが表示されました。
DBConnection.ConnectionError
(Mix) The database for EctoChangesetSample.Repo couldn’t be created: killed`
【対処方法】 下記ウインドウを出し、PostgreSQLを起動
【ポイント】
エラーの原因は、PostgreSQLが起動していなかった為で、起動したら、動くようになりました。
テーブル重複エラーが出た
【対処方法】 下記コマンドを実行
$mix ecto.migrate --step 1
【ポイント】
エラーの原因は、PJを作り直す前にmigrateしてテーブル作成済のところに、再度migrateした為で、
migrateのステップを先頭からやり直したら上手くいきました。
以下を参考にしました。
mix ecto.migrate で重複エラーが起きた時のメモ【調査中】
https://qiita.com/VA-11_Hall-A/items/a8fe72835108ea612d16
感想
環境の部分に時間を多く取られてしまった為、数をこなして、エラーの原因の切り分けをできるようになっていきたいと思いました。
チェンジセットや正規表現については、勉強して今後実装を試していきたいと思います。
環境により、結果やエラーの内容は変わると思いますが、こちらの記事がどなたかの参考になりましたら幸いです。
最後に
@piacerex さん、今回環境周りで詰まっておりましたところ、丁寧に質問に答えてくださり、本当にありがとうございました。
Elixirコミュニティの皆さま、エリジョ(Elixir女子部)や勉強会にて、2020年は大変お世話になりました。
いつもご親切にありがとうございます。
明日は @piacerex さんの「WSL2でElixir本体のビルドとiexバージョン変更」 です! お楽しみに!