Devise、password_required? のオーバーライドで。
Devise という、便利さと窮屈さをひきかえにする gem があります。1
今作っているサービスでは、Devise の validatable を使って email
と password
のバリデーションをするような設定にしているんですが、サービスの仕様により、とある条件のレコードだけはパスワードが空でも保存できるようにしたい、という要件がありました。
Devise でこれを実現するには、Devise 本体で以下のように定義してある password_required?
というメソッドをアプリケーション側でオーバーライドしますね。
Devise ではパスワードの存在確認、文字数制限についてのバリデーションを実行してくれるようになっているのですが、 password_required?
をオーバーライドすることで、それらのバリデーションをどういう条件で実行するかをユーザが任意に決めることができます。
devise/validatable.rb at e72839f4bc18e038e1cb9a0cd24c9aed47cb2183 · plataformatec/devise · GitHub
# app/models/user.rb class User < ApplicationRecord def password_required? # NOTE: self.company.name が "株式会社ぴよぴよ" のユーザだけはパスワードが空でも構わないので、 # パスワードのバリデーションはしない if company.name == "株式会社ぴよぴよ" false else super end end end
これでいっちょあがり〜とひと安心、"株式会社ぴよぴよ" のユーザを使って動作確認をしてみたところ...
ActiveRecord::RecordInvalid (バリデーションに失敗しました: パスワードを入力してください, パスワードを入力してください, パスワードには英小文字、英大文字、数字を全て含めてください。記号は使用できません。):
あれ...バリデーションエラーでてる... つまりバリデーションが実行されているってことだよね...
User モデルのファイルを見てみる
おかしいなあと思いながら、オーバーライドした password_required?
メソッドを pry で止めてみたり、プリントデバッグしてみたりいろいろやりながら、User モデルファイルを改めて眺めてみたところ、...
validates :password, presence: true, format: { with: /\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,64}+\z/, message: "には英小文字、英大文字、数字を全て含めてください。記号は使用できません。" }, if: -> { new_record? || changes['encrypted_password'] }
おーい!自分で presence: true
って書いてるやないかーーーーい!!!\(^o^)/
解決
以下のように修正して解決しました。
validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,64}+\z/, message: "には英小文字、英大文字、数字を全て含めてください。記号は使用できません。" }, if: -> { new_record? || changes['encrypted_password'] }, allow_blank: true
冒頭にも書いたとおり、Devise で設定されているバリデーションは文字数制限と存在確認のみをしています。
devise/validatable.rb at e72839f4bc18e038e1cb9a0cd24c9aed47cb2183 · plataformatec/devise · GitHub
しかし、わたしが作っているサービスの場合、パスワードに使われる文字種も制限をしたいので、そのバリデーションについてはアプリケーション側で実装する必要があります。
ってなわけで、 format
の部分は残したままにしつつ、Devise 側でやっている presence: true
は削除。
さらに、「とある条件のレコードだけはパスワードが空でも保存できるようにしたい」ので、 password
カラムが空欄になることも許容しなきゃいけない。そのため allow_blank: true
も入れました。
Active Record バリデーション | Rails ガイド
おわりに
技術的な記事ってめちゃ久しぶりに書いたのでちょっとドキドキした。
今日書いた内容みたいなポカする人はわたし以外にいると思えないけど(笑)、こんなかんじで "日常系技術ブログ" をモットーにして、書くことのハードルが上がりすぎないようにしつつ続けていけたらいいなー。