この記事は、以下の記事の続きです。
『Railsウィザード形式フォームで新規登録〜Devise+session〜』
https://qiita.com/ATORA1992/items/40fc543742a6df5a17c1
#やりたいこと
ウィザード形式のフォームで、画面遷移するたびにバリデーションをかけたい。
#実装方法
- modelにvalidatesを記述する
- 遷移するたびに、before_actionを呼びだす
- before_action内で、仮のインスタンスを作成し、バリデーションを確認する
これの繰り返しで、やりたいことを実現できます。
#具体例(抜粋)
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
# step1入力項目
validates :nickname, presence: true, length: {maximum: 20}
validates :email, presence: true, uniqueness: true, format: { with: VALID_EMAIL_REGEX }
validates :password, presence: true, length: {minimum: 6, maximum: 128},on: :save_to_session_before_phone
validates :password_confirmation, presence: true, length: {minimum: 6, maximum: 128},on: :save_to_session_before_phone
# step2入力項目
validates :last_name, presence: true
validates :first_name, presence: true
validates :last_name_kana, presence: true
validates :first_name_kana, presence: true
入力フォームに必要なバリデーションを該当modelに記述してください。
class SignupController < ApplicationController
before_action :validates_step1, only: :step2 # step1のバリデーション
before_action :validates_step2, only: :step3 # step2のバリデーション
~省略~
# 各アクションごとに新規インスタンスを作成します
def step1
@user = User.new # 新規インスタンス作成
end
def step2
@user = User.new # 新規インスタンス作成
end
~省略~
# before_actionごとに、遷移元のページのデータをsessionに保管していきます
# 仮でインスタンスを作成しバリデーションチェックを行います
def validates_step1
# step1で入力された値をsessionに保存
session[:nickname] = user_params[:nickname]
session[:email] = user_params[:email]
session[:password] = user_params[:password]
session[:password_confirmation] = user_params[:password_confirmation]
# バリデーション用に、仮でインスタンスを作成する
@user = User.new(
nickname: session[:nickname], # sessionに保存された値をインスタンスに渡す
email: session[:email],
password: session[:password],
password_confirmation: session[:password_confirmation],
last_name: "山田", # 入力前の情報は、バリデーションに通る値を仮で入れる
first_name: "太郎",
last_name_kana: "ヤマダ",
first_name_kana: "タロウ",
~省略~
)
# 仮で作成したインスタンスのバリデーションチェックを行う
render '/signup/step1' unless @user.valid?
end
def validates_step2
# step2で入力された値をsessionに保存
session[:last_name] = user_params[:last_name]
session[:first_name] = user_params[:first_name]
session[:last_name_kana] = user_params[:last_name_kana]
session[:first_name_kana] = user_params[:first_name_kana]
# バリデーション用に、仮でインスタンスを作成する
@user = User.new(
nickname: session[:nickname], # sessionに保存された値をインスタンスに渡す
email: session[:email],
password: session[:password],
password_confirmation: session[:password_confirmation],
last_name: session[:last_name],
first_name: session[:first_name],
last_name_kana: session[:last_name_kana],
first_name_kana: session[:first_name_kana],
~省略~
)
# 仮で作成したインスタンスのバリデーションチェックを行う
render '/signup/step2' unless @user.valid?
end
ウィザードフォームを作っているコントローラーで、バリデーションチェックを行います。
各ページに対応するアクションでは、新規インスタンスの作成を行なってください。
次のページに遷移する前(次のページに対応するアクションを動かす前)にbefore_actionでバリデーションチェック用のアクションを実行します。
before_actionのアクションで行うことは、以下の3つです
- sessionにフォーム情報を保管する
- バリデーションチェック用の仮インスタンスを作成する
- 仮インスタンスを元にバリデーションをチェックする(@user.valid?)
特に重要なのは、仮のインスタンス作成です。
自分は、インスタンスに必要なカラム情報を全て埋めるようにして実装しました。
なので、sessionで値を保管する前の情報は、バリデーションが通るものを仮置きで記述しています。
フォーム量が増えると、仮置きの情報が増えてしまうので、modelでのvalidatesで、以下のようにon: :アクション名として、バリデーションのかかるアクションを限定する方がいいかもしれません。
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
# step1入力項目
validates :nickname, presence: true, length: {maximum: 20}, on: :validates_step1
validates :email, presence: true, uniqueness: true, format: { with: VALID_EMAIL_REGEX }, on: :validates_step1
validates :password, presence: true, length: {minimum: 6, maximum: 128}, on: :validates_step1
validates :password_confirmation, presence: true, length: {minimum: 6, maximum: 128}, on: :validates_step1
# step2入力項目
validates :last_name, presence: true, on: :validates_step2
validates :first_name, presence: true, on: :validates_step2
validates :last_name_kana, presence: true, on: :validates_step2
validates :first_name_kana, presence: true, on: :validates_step2
render '/signup/step1' unless @user.valid?(:validates_step1)
render '/signup/step1' unless @user.valid?(:validates_step2)
#補足
バリデーションチェックしたあと、エラーメッセージをどうやって取得するか・表示するかは、別記事を参考にしてみてください。
https://qiita.com/ATORA1992/items/218f17deb66c82f27fbc