未経験からのフルスタックエンジニア

スキルをつけよう!未経験からフリーランスエンジニアへの成長記録

【Rails】ウィザード形式の登録フォームでバリデーション

この記事は、以下の記事の続きです。

atora1992.hatenablog.com

やりたいこと

ウィザード形式のフォームで、画面遷移するたびにバリデーションをかけたい。

実装方法

  1. modelにvalidatesを記述する
  2. 遷移するたびに、before_actionを呼びだす
  3. 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つです

  1. sessionにフォーム情報を保管する
  2. バリデーションチェック用の仮インスタンスを作成する
  3. インスタンスを元にバリデーションをチェックする(@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)

補足

バリデーションチェックしたあと、エラーメッセージをどうやって取得するか・表示するかは、別記事を参考にしてみてください。

atora1992.hatenablog.com