サービスを作っていると「パスワードやメールアドレスの確認用入力フォームを作りたいな〜」みたいな時ありますよね。
イメージこんな感じ。
(パスワードだったらユーザー認証のライブラリがだいたいやってくれてるような気もしますが。。)
Rails標準のヘルパーでめちゃくちゃ簡単に実現できます。
今回はユーザーのメールアドレスの確認フォームということを想定して、対象のカラムはemailとします。
やること
- email_confirmationのフォームを用意する
- email_confirmationをストロングパラメーターで許可する
- emailのバリデーションにconfirmation: trueを追加する
これだけ。めちゃ簡単
email_confirmationのフォームを用意
_form.html.slim
= f.text_field :name = f.text_field :email = f.text_field :email_confirmation
ストロングパラメーターで許可
users_controller.rb
class UsersController < ApplicationController ・ ・ ・ private def user_params params_require(:user).parmit(:id, :name, :email, :email_confirmation) end end
(わかりやすくするためにだいぶ割愛)
まあここまでは普通というか特につまづくところもないのですが、モデルのバリデーション周りでちょっと頭を使った。
confirmation: trueを追加
models/user.rb
validates :email, presence: true, email_format: true, uniqueness: true, confirmation: true
で、リファレンスにこう書いてあるんだけどさ。。
2つのテキストフィールドで受け取る内容が完全に一致する必要がある場合に使います。
このチェックは、email_confirmationがnilでない場合のみ行われます。確認を必須にするには、確認用の属性について存在チェックも追加してください。
確認欄に何も入力しないと、nilじゃなくて「""」がパラメーターで渡されるから、email_confirmationを必須入力にしなくても、この状態だと結局毎回必ず完全一致のチェックが効いてしまうんですよ。まあ、そうしないとブランクおっけーになっちゃうもんね。
私の場合、特定のケースのみ完全一致のチェックをすっ飛ばしたかったので、ここでちょっと悩んだ。
解決
confirmation: trueだけ切り分けてwith_optionで呼び出すことで成功。
models/user.rb
validates :email, presence: true, email_format: true, uniqueness: true with_options if: hogehoge do validates :email, confirmation: true end def hogehoge return true if name == 'hogehoge' end
名前がhogeさんのときだけ、確認用メールアドレスの完全一致チェックが入ります。
(実際そのような仕様は存在しないが)
特定の条件下のみでバリデーションを適用させたいときの方法はいくつかあるけど、with_optionsを使うとtrueが返ってきたときだけバリデーションを実行してくれて、かつ条件部分を別メソッドに切り分けたりもできるので結構便利。
まとめ
- 確認入力欄を作りたいときはname属性をカラム名_confirmationとする
- バリデーションでconfirmation: trueを追加すると完全一致チェックをしてくれる
- カラム名_confirmationに渡ってきた値がnilの場合は完全一致チェックがされない
余談
メールアドレスの入力欄を2回設ける仕様って普段結構いろんなサービスで目にするけど、昨今2段階認証が当たり前になっているし、2回入力させる意味ってほとんど無いんじゃないかな〜とこれ書いてて思った。。
一生懸命実装したけど、「これってそもそも必要あったの?」「ここにこれだけの工数割くのって有益だった?」って後から思うことってよくありますよね。。
技術力が追いついてくると、こういうのも実装する前に気がつけるようになるんだろうな...!