deviseのコントローラをカスタマイズしてウィザード形式の新規登録画面を作成する
deviseをカスタマイズしてウィザード形式のユーザー新規登録画面を実装しました。
ユーザーの情報と、住所の情報を2ページに分けて記入させるようにしました。
ウィザード形式?
アプリのユーザー登録の際に、最初はアドレスやパスワード入力して、次のページで住所やら過去の経歴やら入力させられたことはありませんか?
あんな感じでユーザーに対話形式で操作を誘導していく機能です。
今回はユーザー情報、住所情報の必要なデータがすべてバリデーションクリアして保存できる状態になって一気に保存する仕組みで作っています。
deviseのインストール〜モデル生成
これは参考サイトでいっぱい紹介されているので割愛します。
モデルはUserモデルとAddressモデルを用意しておきます。
usersテーブルとaddressesテーブルにはhas_oneの関係があります。(usersが親)
コントローラ生成
以下コマンドを実行する。
$ rails g devise:controllers users
するとapp/controllers/usersにコントローラがいくつか生成される。
今回は新規登録なので、registrations_controller.rbをいじっていきます。
ルーティングの設定
続いてregistrations_controller.rbを利用するためのルーティングを設定します。
Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'users/registrations'
}
end
createアクションをカスタム
まずはユーザー情報をカスタムするためにcreateアクションをカスタマイズしていきます。
def create
@user = User.new(sign_up_params)
unless @user.valid?
flash.now[:alert] = @user.errors.full_messages
render :new and return
end
session["devise.regist_data"] = {user: @user.attributes}
session["devise.regist_data"][:user]["password"] = params[:user][:password]
@address = @user.build_address
render :new_address
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys:
[:nickname, :birthday, :first_name,:last_name])
end
上から。
@user = User.new(sign_up_params)
ストロングパラメータで取得したデータのuserオブジェクトを作成してます。
ここで疑問なのがストロングパラメータのメソッド名がconfigure_sign_up_paramsなのにsign_up_paramsで呼び出せている点。
きっとdeviseの仕様だと思いますが。。。
その後、userオブジェクトのバリデーションを確認します。
unless @user.valid?
flash.now[:alert] = @user.errors.full_messages
render :new and return
end
無事にバリデーション通ったらsessionにuserのデータをattributesメソッドを使用して保存します。
session["devise.regist_data"] = {user: @user.attributes}
session["devise.regist_data"][:user]["password"] = params[:user][:password]
ここで注意したいのがパスワードはattributesメソッドでは追加できないということ。
paramsから取得して別で追加してあげます。
その後、build_addressメソッドを使用して関連づけられたaddressオブジェクトを使用します。
@address = @user.build_address
build_addressメソッドはhas_oneのアソシエーションを設定すると使用できるようになります。関連づけのあるnewメソッドのようなものです。
Addressを保存する処理を記述
先ほどのcreateアクションでrender :new_addressと記述したためルーティングとアクション、ビューを用意する。create_addressも用意する。
ルーティング
Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'users/registrations'
}
devise_scope :user do
get 'addresses', to: 'users/registrations#new_address'
post 'addresses', to: 'users/registrations#create_address'
end
end
コントローラ
def create
@user = User.new(sign_up_params)
unless @user.valid?
flash.now[:alert] = @user.errors.full_messages
render :new and return
end
session["devise.regist_data"] = {user: @user.attributes}
session["devise.regist_data"][:user]["password"] = params[:user][:password]
@address = @user.build_address
render :new_address
end
def new_address
end
def create_address
@user = User.new(session["devise.regist_data"]["user"])
@address = Address.new(address_params)
unless @address.valid?
flash.now[:alert] = @address.errors.full_messages
render :new_address and return
end
@user.build_address(@address.attributes)
@user.save
sign_in(:user, @user)
redirect_to root_path
end
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys:
[:nickname, :birthday, :first_name, :last_name])
end
def address_params
params.require(:address).permit(:ship_family_name, :ship_first_name, :ship_family_name_kana,
:ship_first_name_kana, :postal_code, :prefecture,
:prefecture_id, :municipality, :block_number, :apartment_name,
:phone_number)
end
さきほどsessionにuserオブジェクトのデータを保存したので、それを用いてcreate_addressアクションでもuserオブジェクトを生成します。
あとは先ほどとほぼほぼ同じで、addressオブジェクトのバリデーションを確認して、通ったら保存します。
ここで注意したいのが、addressesテーブルに外部キーを設定していると、バリデーションに引っかかってしまいます。
そのため、モデルでoptional: trueして外部キーにnullが入ることを許可しています。
class Address < ApplicationRecord
belongs_to :user, optional: true
end
まとめ
意外と簡単にできました!
この記事が気に入ったらサポートをしてみませんか?