Rails  ウィザード形式のユーザー登録機能実装 コントローラの記述(session, ハッシュ等)を紐解いてみた

####はじめに
チーム開発で、メルカリを模したアプリを開発しました。
その中で、”ウィザード形式”のユーザー登録機能を実装しました。

ウィザード形式とは
ユーザー登録ページが複数ページにわたり、全ての入力を終えてようやく登録される形式のことをいいます。

例
・1ページ目で名前・生年月日など基本情報を入力。ボタンを押して2ページ目へ。
・2ページ目で住所を入力。登録ボタンを押す。
・両ページに入力された情報が登録される。
といった具合です。

ウィザード形式においてポイントとなる"session"に関するコーディングを、
deviseのregistrations_controllerの
createアクション（登録1ページ目）と、
create_addressアクション（登録2ページ目）に
記述しました。

※今回、usersテーブルとship_addressesテーブルを設定しました。
　最終的に、登録1ページ目のデータが前者に、2ページ目のデータが後者に保存されます。

####実装後にやってみたこと
そのコーディングで具体的に何をしているのか？自分なりにまとめてみました。

■自分の中のあるある（言いたい）
User.new(session["devise.regist_data"]["user"])の（　）内のような独特な記載のコードを目にすると、”なんとなくこんなことしてるんだろな〜”ぐらいに軽く流し読みしがち。
↓
今回チームメンバーにコーディング解説（！）する場面がありましたので、良い機会だと思い、メンターに質問するなどしてコーディング詳細を調べてみました。

■そもそもsessionとは
こちらの記事がわかりやすくてお世話になりました！😀
https://qiita.com/ozackiee/items/4ee774c81b2a0c571c05

■sessionを使う1つのメリット
1ページ目の登録を終え、2ページ目に進むも、途中で入力中断、のような状況の時に、
中途半端な情報を登録せずに済みます。
sessionをうまく使って、1ページ目・2ページ目ともに入力して初めて登録完了するように
コーディングしています。

■環境
rails (5.2.4.2)
devise (>= 4.7.1)


####registrations_controllerに書いたコードと解説（解説もセットでご覧ください）
```registrations_controller.rb
  def create
    @user = User.new(sign_up_params) #登録1ページ目から送られてきたパラメータを@userに代入
    unless @user.valid? #validメソッドを使ってバリデーションチェック
      flash.now[:alert] = @user.errors.full_messages #入力漏れがあればエラーメッセージを表示
      render :new and return #and returnを使って条件分岐を明示的に終了させている。
    end
   
    session["devise.regist_data"] = {user: @user.attributes} 
    #sessionにハッシュオブジェクトで情報保持させるため、attributesメソッドでデータ整形。
    #user: というようにシンボル型で記述している。

    session["devise.regist_data"][:user][:password] = params[:user][:password] 
    #前述ではパスワードを代入出来ていないので、この行で代入。
    #params[:user][:password]において、paramsの中身（userモデルのpasswordカラム）から値を取り出している。ネスト構造な書き方。
    # （params[:password]ではなく、params[:user][:password]という書き方で、モデル・カラムという順番で指定している）
    #その値をsession["devise.regist_data”]の中の[:user]というハッシュの[:password]というキーのバリューに代入している。
　　#今回ひとつ前のコードでシンボル型を用いているので、ここのコードも型を合わせている。
   #もしもひとつ前のコードで文字列型（"user"）を用いている場合は、ここのコードも文字列型にする必要がある。

    @address = @user.build_ship_address 
    #build_ship_addressメソッドはhas_one :ship_addressのアソシエーションを設定していると使用可。関連づけのあるnewメソッドのようなもの。
    render :new_address #登録2ページ目に遷移
  end

  def create_address
    @user = User.new(session["devise.regist_data"]["user"])
    #session["devise.regist_data”]の中の["user”]というハッシュの情報を@userに代入している。
    #userという同じハッシュがアクションをまたぐ（create~create_address）と、create_addressアクションにおいては自動的に文字列になってしまう。
    #そのためcreate_addressアクションでは文字列表記で指定しないといけない。
    #binding.pryで実際に検証すると、文字列表記でパラメータが飛んでいることが確認できる。

    @address = ShipAddress.new(address_params)
    unless @address.valid?
      flash.now[:alert] = @address.errors.full_messages
      render :new_address and return
    end
    @user.build_ship_address(@address.attributes) #送られてきたparamsをbuild_ship_addressを用いて@userに代入
    @user.save
    session["devise.regist_data"]["user"].clear #sessionを明示的に削除 セキュリティ上必要
    sign_in(:user, @user) #登録後ログイン状態になるようにしている
    redirect_to complete_users_path
  end
```
という感じで
1つ1つの記載がどんなオブジェクト・メソッドなのか紐解いてみました。
いざ自分でエディタにコメントで意味を書き出してみると、かなり良いアウトプットになるなと感じました。
1行1行細かく見ていくのでそれなりに時間はかかりましたが、とても勉強になったので、やって良かったです。
（チームメンバーのみんなに感謝！！）

何かありましたらご指摘等いただければ幸いです。
以上、ご覧いただきありがとうございました！