指定した時だけバリデーションを実行したい
指定した時だけバリデーションを実行したい
開発をしているタイミングでバリデーションを実行したい時と、バリデーションを実行したくない時が発生したので、こちらにまとめます。
コードは、以下のようになっています。
[app/models/user.rb] class User < ApplicationRecord authenticates_with_sorcery! validates :password, length: { minimum: 10 }, if: -> { new_record? || changes[:crypted_password] } validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] } validates :password, presence: true validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] } validates :email, uniqueness: { case_sensitive: false }, presence: true validates :name, presence: true has_many :cooking_memories, dependent: :destroy end
[app/controllers/users_controller.rb] class UsersController < ApplicationController before_action :require_login, only: %i[show edit update] def new @user = User.new end def create @user = User.new(user_params) if @user.save flash[:success] = t '.success_message' redirect_to login_path else flash.now[:danger] = t '.error_message' render :new end end def show @user = User.find(current_user.id) end def edit @user = User.find(current_user.id) end def update ① @user = User.find(current_user.id) if @user.update(profile_params) flash[:success] = t '.success_message' redirect_to profile_path else flash.now[:danger] = t '.error_message' render :edit end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end def profile_params params.require(:user).permit(:name, :email) end end
ユーザーの新規登録時は、[ニックネーム]、[Eメール]、[パスワード]、[パスワード再確認]の全部の項目の入力を必要にしたいが、
プロフィール画面では、[ニックネーム]、[Eメール]だけの入力で編集できるようにしたいが[パスワード]、[パスワード再確認]にpresence: true
のバリデーションを設定しているので更新時に以下のようにエラーになってしまう。
①のupdate
アクション(ユーザー情報の更新)をする時は、[ニックネーム]、[Eメール]のみバリデーションが実行されるようにしたい。
そんな時にバリデーションのカスタムコンテキストというのがあると分かったが、通常とは逆の設定にしたいとなりました。
つまり、カスタムコンテキストを記載した場合だけバリデーションが実行されないようにしたい。
結果以下のように記載することで、カスタムコンテキストを記載した場合だけバリデーションが実行されないようにできた!!
[app/models/user.rb] class User < ApplicationRecord authenticates_with_sorcery! validates :password, length: { minimum: 10 }, if: -> { new_record? || changes[:crypted_password] } validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] } validates :password, presence: true, unless: -> { validation_context == :not_password_validation } ① validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] } validates :email, uniqueness: { case_sensitive: false }, presence: true validates :name, presence: true has_many :cooking_memories, dependent: :destroy end
[app/controllers/users_controller.rb] class UsersController < ApplicationController before_action :require_login, only: %i[show edit update] def new @user = User.new end def create @user = User.new(user_params) if @user.save flash[:success] = t '.success_message' redirect_to login_path else flash.now[:danger] = t '.error_message' render :new end end def show @user = User.find(current_user.id) end def edit @user = User.find(current_user.id) end def update @user = User.find(current_user.id) @user.attributes = profile_params if @user.save(context: :not_password_validation) flash[:success] = t '.success_message' redirect_to profile_path else flash.now[:danger] = t '.error_message' render :edit end end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end def profile_params params.require(:user).permit(:name, :email) end end
参考記事
特定のvalidationをスキップする - プログラミングのメモ帳
Rails のバリデーションを特定のコンテキスト「以外」で実行させる | Webシステム開発/教育ソリューションのタイムインターメディア
バリデーションでコンテキストを活用する | ⬢ Appirits spirits