Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

この記事は、以下の記事の続きです。
『Railsウィザード形式フォームで新規登録〜Devise+session〜』
https://qiita.com/ATORA1992/items/40fc543742a6df5a17c1

やりたいこと

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

実装方法

  1. modelにvalidatesを記述する
  2. 遷移するたびに、before_actionを呼びだす
  3. before_action内で、仮のインスタンスを作成し、バリデーションを確認する

これの繰り返しで、やりたいことを実現できます。

具体例(抜粋)

user.rb
 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に記述してください。

signup_controller.rb
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: :アクション名として、バリデーションのかかるアクションを限定する方がいいかもしれません。

user.rb
 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
signup_controller.rb
render '/signup/step1' unless @user.valid?(:validates_step1)
render '/signup/step1' unless @user.valid?(:validates_step2)

補足

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

ATORA1992
Webエンジニアになるべく主にHTML、CSS、Ruby、Ruby on Railsを主として勉強中の身です。 勉強のアウトプットの場として、学習内容をアップしています。フリーランス。案件募集中。 Twitter: @ATORA1992
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away