「:on」でバリデーション発動のタイミングを指定する
バリデーションが発動して欲しくないときに発動してしまって困った時の話です。
概要
deviseを使ったユーザー管理機能を実装
↓
Userモデルにパスワードに関するバリデーションを追加
↓
マイページでユーザー情報を編集できるように実装したい
↓
current_user.updateで更新しようとしたらパスワードのバリデーションが発動して更新できない
問題点
ユーザーを新規登録した時、パスワードは文字列がそのままデータベースに保存されるわけではないですよね。多分暗号化されているはず。
そのためユーザー情報を更新(つまりcurrent_user.update)しようとした時、passwordの値は空になっています。
deviseはうまいこと対応してくれるのでしょうが、Userモデルに自分で設定したバリデーションには引っかかってしまうようです。
User.rb
にはパスワードが英数字混合であるように指定していました。
PASSWORD_REGEX = /\A(?=.*?[a-zA-Z])(?=.*?[\d])[a-zA-Z\d]+\z/.freeze validates :password, format: { with: PASSWORD_REGEX, message: "は英数字混合で入力してください" }
解決
初めは、ユーザーがログインしている時はバリデーションを発動しないように、ifを使ってなんとかしようとしました。
if !current_user.present? PASSWORD_REGEX = /\A(?=.*?[a-zA-Z])(?=.*?[\d])[a-zA-Z\d]+\z/.freeze validates :password, format: { with: PASSWORD_REGEX, message: "は英数字混合で入力してください" } end
しかし、current_userなんてものはないと言われてしまいました。モデルの中では使えないのか。
さらに調べていたら、バリデーションが発動するタイミングを指定する方法を発見。on:
で指定すればOKらしい。
パスワードのバリデーションが発動して欲しいのは新規登録の時だけで、更新の時は発動して欲しくないので、on: :create
で発動のタイミングを指定しました。
PASSWORD_REGEX = /\A(?=.*?[a-zA-Z])(?=.*?[\d])[a-zA-Z\d]+\z/.freeze validates :password, format: { with: PASSWORD_REGEX, message: "は英数字混合で入力してください", on: :create }
そうしたらいけました。無事にユーザー情報を編集して更新する機能が実装できました。こんなに簡単だったとは。
まとめ
- バリデーション発動のタイミングを指定する時は
:on
オプション