0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ウィザード形式でユーザ登録のフォームを作成してみた②-1 〜viewとcontroller〜

0
Last updated at Posted at 2020-06-08

【この記事の説明】

現在、私はプログラミングスクールでプログラミング(主にRuby)の勉強をしています。
そして、その一環でチーム開発(メルカリもどきのサイト作成)を行っており、私はその中で記事のタイトルにあるように、ウィザード形式でユーザの登録ができるようにする作業を担当致しました。
又、スクールからの指示で、この登録フォームにはdeviseを使用するようにとのことでした。

この記事は、その担当作業についてまとめたものになります。

【作業】

ここから私が行った作業(そこで困ったこと)を記事として記載していこうと思います
※この記事では、viewとcontrollerについて記載したいと思います

view、controllerの作成

本当はviewはview、controllerはcontrollerで記載したいのですが、この二つは密接に関わり合う為、別々に説明ができません。ですので、一緒に説明していきたいと思います
又、ここでは、view作成の細かいところの記載はしません
あくまでもユーザー登録に必要な部分のみの記載となります

では、以下にcontrollerとviewのコードを記載します
(前の記事で記載しましたが、ウィザード形式で3ページ分の登録ページを作成している為、viewは3つ記載します
詳しくはウィザード形式でユーザ登録のフォームを作成してみたをご覧ください)

controller

/app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController

  # GET /resource/sign_up
  def new
    super
  end
  
  def create
    @user = User.new(session["devise.regist_data"]["user"])
    @profileaddress = Profileaddress.new(session["profileaddress"])
    @deliveryaddress = Deliveryaddress.new(deliveryaddresses_params)
    unless @deliveryaddress.valid?
      flash.now[:alert] = @deliveryaddress.errors.full_messages
      render :new_deliveryaddresses and return
    end
    @user.build_profileaddress(@profileaddress.attributes)
    @user.build_deliveryaddress(@deliveryaddress.attributes)
    if @user.save
      session["devise.regist_data"]["user"].clear
      session["profileaddress"].clear
      sign_in(:user,@user)
      redirect_to root_path
    else
      render :new
    end
  end

  def new_profileaddresses
    @user = User.new(birthday_save)
    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]
    @profileaddress = @user.build_profileaddress
  end

  def new_deliveryaddresses
    user = User.new(session["devise.regist_data"]["user"])
    @profileaddress = Profileaddress.new(profileaddress_params)
    unless @profileaddress.valid?
      flash.now[:alert] = @profileaddress.errors.full_messages
      render :new_profileaddresses and return
    end
    user.build_profileaddress(@profileaddress.attributes)
    session["profileaddress"] = @profileaddress.attributes
    @deliveryaddress = user.build_deliveryaddress
  end

  private
    def birthday_save
      date = user_params
      year = date[:"birthday(1i)"]
      month = date[:"birthday(2i)"]
      day = date[:"birthday(3i)"]
      if year.empty? || month.empty? || day.empty?
        return
      end
      # 年月日別々できたものを結合して新しいDate型変数を作り,paramsに数字化したDataをくっつけました
      birthday = Date.new(year.to_i,month.to_i,day.to_i)
      params.require(:user).permit(:email,:password,:password_confirmation,:nickname,:family_name,:given_name,:family_name_kana,:given_name_kana).merge(birthday: birthday)
    end
    def user_params
      params.require(:user).permit(:email,:password,:password_confirmation,:nickname,:family_name,:given_name,:family_name_kana,:given_name_kana).merge("birthday(1i)": params[:birthday][:"birthday(1i)"]).merge("birthday(2i)": params[:birthday][:"birthday(2i)"]).merge("birthday(3i)": params[:birthday][:"birthday(3i)"])
      # paramsの中のカラム→:email,:password,:password_confirmation,:nickname,:family_name,:given_name,:family_name_kana,:given_name_kana,:birthday(1i),:birthday(2i),:birthday(3i)
    end
    def profileaddress_params
      params.require(:profileaddress).permit(:postal_code, :prefectures,:city,:address,:building)
    end
    def deliveryaddresses_params
      params.require(:deliveryaddress).permit(:family_name,:given_name,:family_name_kana,:given_name_kana,:postal_code,:prefectures,:city,:address,:building,:phone_number)
    end
end

view(1ページ目:ユーザ情報)

/app/views/users/registrations/new.html.haml
.input-top
  = render partial: '/template/input-top'
  
  .login-main
    .login-main__title
      会員情報入力
    .login-main__content
      .login-main__content__form
        = form_with(model: @user, url: profileaddresses_path,local: true,method: :post) do |f|  

          .form-group
            ニックネーム
            %span.required
              必須
            %br
            .field
              = f.text_field :nickname, autofocus: true, autocomplete: "nickname",placeholder: "例)フリマ太郎",class: "default"            
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:nickname).each do |message|
                      %li{style: "color:red"}
                        = message

          .form-group
            メールアドレス
            %span.required
              必須
            %br
            .field
              = f.text_field :email, autofocus: true, autocomplete: "email", placeholder: "PC・携帯どちらでも可", class:"default"         
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:email).each do |message|
                      %li{style: "color:red"}
                        = message

          .form-group
            パスワード
            %span.required
              必須
            %br
            .field
              = f.password_field :password, autocomplete: "new-password", placeholder: "7文字以上",class: "default"
            %p.info 英字と数字の両方を含めて設定してください
            - if @user.errors.any?
              .error_explanation
                %h2
                  - I18n.t("errors.messages.not_saved",                 |
                    count: resource.errors.count,                       |
                    resource: resource.class.model_name.human.downcase) |
                %ul
                  - @user.errors.full_messages_for(:password).each do |message|
                    %li{style: "color:red"}
                      = message

          .form-group 
            パスワード確認用
            %span.required
              必須
            %br
            .field
              = f.password_field :password_confirmation, autocomplete: "new-password",placeholder: "もう一度パスワードを入力してください",class:"default"
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:password_confirmation).each do |message|
                      %li{style: "color:red"}
                        = message

          .form-group
            本人確認
            %p.info-text 安心安全にご利用いただく為にお客様の本人情報の登録にご協力ください他のお客様に公開されることはありません

          .form-group
            お名前(全角)
            %span.required
              必須
            %br
            .field
              = f.text_field :family_name, autofocus: true, autocomplete: "family_name",placeholder: "例)山田",class: "default half"           
              = f.text_field :given_name, autofocus: true, autocomplete: "given_name",placeholder: "例)太郎",class: "default half__right"
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:family_name).each do |message|
                      %li{style: "color:red"}
                        = message
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:given_name).each do |message|
                      %li{style: "color:red"}
                        = message

          .form-group
            お名前カナ(全角)
            %span.required
              必須
            %br
            .field
              = f.text_field :family_name_kana, autofocus: true, autocomplete: "family_name_kana",placeholder: "例)ヤマダ",class: "default half"           
              = f.text_field :given_name_kana, autofocus: true, autocomplete: "given_name_kana",placeholder: "例)タロウ",class: "default half__right"
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:family_name_kana).each do |message|
                      %li{style: "color:red"}
                        = message
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:given_name_kana).each do |message|
                      %li{style: "color:red"}
                        = message

          .form-group
            生年月日
            %span.required
              必須
            %br
            .field
              != sprintf(f.date_select(:birthday, prefix:'birthday',with_css_classes:'XXXXX', prompt:"--",use_month_numbers:true, start_year:Time.now.year, end_year:1900, date_separator:'%s'),'年','月')+'日'
                  
              - if @user.errors.any?
                .error_explanation
                  %h2
                    - I18n.t("errors.messages.not_saved",                 |
                      count: resource.errors.count,                       |
                      resource: resource.class.model_name.human.downcase) |
                  %ul
                    - @user.errors.full_messages_for(:birthday).each do |message|
                      %li{style: "color:red"}
                        = message
        

          .form-group
            .actions
              = f.submit "次へすすむ",class: "submit"
            -# %input.submit{type: "submit", value: "次へすすむ"}

            -# 実験的にページ移動の為のリンクです。ウィーザード形式に後になります
            -# =link_to '会員登録情報その2', new2_users_path
            
  .login-footer
    = render partial: '/template/input-bottom'

view(2ページ目:ユーザー本人の住所)

/app/views/users/registrations/new_profileaddresses.html.haml
.input-top
  = render partial: '/template/input-top'
  
  .login-main
    .login-main__title
      ご本人様情報入力任意

    .login-main__content
      .login-main__content__form
        = form_with(model: @profileaddress,url: deliveryaddresses_path,local: true,method: :post) do |f|

          .form-group
            郵便番号  
            %span.any
              任意
            %br 
            .field
              = f.text_field :postal_code, autofocus: true, autocomplete: "postal_code",placeholder: "ーーー",class: "default"
              -if @profileaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @profileaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("郵便番号")
                          = message.delete!("Translation missing: ja")

                    
          .form-group
            都道府県
            %span.any
              任意
            %br
            .field 
              = f.select :prefectures, Profileaddress.prefectures.keys, {},placeholder: "選択してください",class: "default"
          .form-group
            市区町村
            %span.any
              任意
            %br 
            .field
              = f.text_field :city, autofocus: true, autocomplete: "city",placeholder: "ーーー",class: "default"
              -if @profileaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @profileaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("市区町村")
                          = message.delete!("Translation missing: ja")

          .form-group
            番地
            %span.any
              任意
            %br 
            .field
              = f.text_field :address, autofocus: true, autocomplete: "address",placeholder: "ーーー",class: "default" 
              -if @profileaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @profileaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("番地")
                          = message.delete!("Translation missing: ja")
          .form-group
            マンション名など部屋号室
            %span.any
              任意
            .field 
              = f.text_field :building, autofocus: true, autocomplete: "building",placeholder: "ーーー",class: "default" 
              -if @profileaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @profileaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("マンション")
                          = message.delete!("Translation missing: ja")
            %p.info 本人情報は正しく入力してください会員登録後修正するにはお時間を頂く場合がございます
          
          .form-group
            .action
              = f.submit "次へすすむ",class: "submit"
            
  .login-footer
    = render partial: '/template/input-bottom'

view(3ページ目:お届け先住所)

/app/views/users/registrations/new_deliveryaddresses.html.haml
.input-top
  = render partial: '/template/input-top'
  
  .login-main
    .login-main__title
      お届け先住所入力
    .login-main__content
      .login-main__content__form
        = form_with(model: @deliveryaddress,url: user_registration_path,local: true) do |f|

          .form-group
            お名前(全角)
            %span.required
              必須
            %br
            .field
              = f.text_field :family_name, autofocus: true, autocomplete: "family_name",placeholder: "例)山田",class: "default half"           
              = f.text_field :given_name, autofocus: true, autocomplete: "given_name",placeholder: "例)太郎",class: "default half__right"       
              -if @deliveryaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @deliveryaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("名字は")
                          = message.delete!("Translation missing: ja")
              -if @deliveryaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @deliveryaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("名前は")
                          = message.delete!("Translation missing: ja")
          .form-group
            お名前カナ(全角)
            %span.required
              必須
            %br
            .field
              = f.text_field :family_name_kana, autofocus: true, autocomplete: "family_name_kana",placeholder: "例)ヤマダ",class: "default half"           
              = f.text_field :given_name_kana, autofocus: true, autocomplete: "given_name_kana",placeholder: "例)タロウ",class: "default half__right"
              -if @deliveryaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @deliveryaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("名字(カナ)は")
                          = message.delete!("Translation missing: ja")
              -if @deliveryaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @deliveryaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("名前(カナ)は")
                          = message.delete!("Translation missing: ja")
          .form-group
            郵便番号 
            %span.required
              必須
            %br 
            .field
              = f.text_field :postal_code, autofocus: true, autocomplete: "postal_code",placeholder: "ーーー",class: "default"
              -if @deliveryaddress.errors.any?
                .alert.alert-warning
                  %ul
                    - @deliveryaddress.errors.full_messages.each do |message|
                      %li{style: "color:red"} 
                        - if message.include?("郵便番号")
                          = message.delete!("Translation missing: ja")
            .form-group
              都道府県 
              %span.required
                必須
              %br         
              .field 
                = f.select :prefectures, Deliveryaddress.prefectures.keys, {},placeholder: "選択してください",class: "default"
            .form-group
              市区町村 
              %span.required
                必須
              %br            
              .field
                = f.text_field :city, autofocus: true, autocomplete: "city",placeholder: "ーーー",class: "default" 
                -if @deliveryaddress.errors.any?
                  .alert.alert-warning
                    %ul
                      - @deliveryaddress.errors.full_messages.each do |message|
                        %li{style: "color:red"} 
                          - if message.include?("市区町村")
                            = message.delete!("Translation missing: ja")
            .form-group
              番地
              %span.required
                必須
              %br             
              .field
                = f.text_field :address, autofocus: true, autocomplete: "address",placeholder: "ーーー",class: "default" 
                -if @deliveryaddress.errors.any?
                  .alert.alert-warning
                    %ul
                      - @deliveryaddress.errors.full_messages.each do |message|
                        %li{style: "color:red"} 
                          - if message.include?("番地")
                            = message.delete!("Translation missing: ja")
            .form-group
              マンション名など部屋号室
              %span.any
                任意
              %br
              .field 
                = f.text_field :building, autofocus: true, autocomplete: "building",placeholder: "ーーー",class: "default"  
                -if @deliveryaddress.errors.any?
                  .alert.alert-warning
                    %ul
                      - @deliveryaddress.errors.full_messages.each do |message|
                        %li{style: "color:red"} 
                          - if message.include?("マンション")
                            = message.delete!("Translation missing: ja")
            .form-group
              電話番号
              %span.any
                任意
              %br
              .field 
                = f.text_field :phone_number, autofocus: true, autocomplete: "phone_number",placeholder: "ーーー",class: "default" 
                -if @deliveryaddress.errors.any?
                  .alert.alert-warning
                    %ul
                      - @deliveryaddress.errors.full_messages.each do |message|
                        %li{style: "color:red"} 
                          - if message.include?("電話番号")
                            = message.delete!("Translation missing: ja")
          .form-group
            %p.info-text__end 登録するのボタンを押すことにより利用規約に同意したものとみなします
            .action
              = f.submit "登録する",class: "submit" 

  .login-footer
    = render partial: '/template/input-bottom'

⦅苦難したところ⦆

1ページ目は主にユーザ情報の入力部分となります
入力フォームには現在推奨されているform_withの方を使用しています

ここで、まず私が苦難したところは以下の部分です

 = form_with(model: @user, url: profileaddresses_path,local: true,method: :post) do |f|  

url: profileaddresses_pathの部分に注目してください。

ちなみに、普通にdeviseで作成するとここは

= form_with(model: @user, url: user_registration_path) do |f|

となっていると思います
そうurl: user_registration_pathとなっているのです
私もこれを直すと思っていませんでした

なぜなら、newアクションを通したviewの次はcreateという固定概念があったからです
しかし、createはデータを保存するアクションです
そして、今回のウィザード形式では、データを保存するのは3ページ目なのでcreateアクションは3ページ目のviewの後にくるアクションだったのです

では、ここでurl: profileaddresses_pathで送られたデータはどこに送られるのでしょうか?
ここでルーティングを確認したいと思います

ターミナル(必要部分のみ記載)
 Prefix Verb   URI Pattern                                                                              Controller#Action
         profileaddresses POST   /profileaddresses(.:format)                                                              users/registrations#new_profileaddresses 

ここでわかるように、newのview(ウィザード形式1ページ目)で入力されたデータはnew_profileaddressesアクションに送信されました
そして、new_profileaddressesアクションでデータは一時保存され(詳しいことは別記事に記載します)、そのままnew_profileaddressesのviewへと移動します

では、次に2ページ目のviewを確認してみます

= form_with(model: @profileaddress,url: deliveryaddresses_path,local: true,method: :post) do |f
ターミナル(必要部分のみ記載)
 Prefix Verb   URI Pattern                                                                              Controller#Action
        deliveryaddresses POST   /deliveryaddresses(.:format)                                                             users/registrations#new_deliveryaddresses 

上記を見てもらえれば、1ページ目と同じ動きをしていることがわかると思います

では、3ページ目はどうでしょうか?

 = form_with(model: @deliveryaddress,url: user_registration_path,local: true) do |f|
ターミナル(必要部分のみ記載)
 Prefix Verb   URI Pattern                                                                              Controller#Action
        user_registration PATCH  /users(.:format)                                                                         users/registrations#update
                          PUT    /users(.:format)                                                                         users/registrations#update
                          DELETE /users(.:format)                                                                         users/registrations#destroy
                          POST   /users(.:format)                                                                         users/registrations#create
 

3ページ目では、url: user_registration_pathにデータを送信しています
ターミナルを確認すれば、これはusers/registrations#createとなります
つまり、createアクションにデータを送信し、1ページ目、2ページ目で一時保存したデータと3ページ目で入力されたデータを一緒に保存してユーザ登録を完了します

⦅結論⦆

view1ページ目(new.html.haml)
 =>入力
  =>入力データ送信(データを一時保存するアクションへと送信)
   =>アクションで一時保存
    =>view2ページ目(一つ前のアクションと同じ名前のview)
     =>入力
      =>入力データ送信(データを一時保存するアクションへと送信)
       =>アクションで一時保存
        =>view3ページ目(一つ前のアクションと同じ名前のview)
         =>入力
          =>入力データ送信
           =>createアクションにて全ての入力データを保存(ユーザ登録する)
この形がウィザード形式であり、データを送信する時はデータを一時保存するアクションへと送信することを忘れないようにします

【次の記事】

この記事では、ウィザード形式のデータの大まかな動きを記載しました
次の記事ではcontroller内について詳しく記載していきます

次の記事ウィザード形式でユーザ登録のフォームを作成してみた②-2 〜viewとcontroller〜

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?