[RUBY] [Rails] Implementation of new registration function in wizard format using devise

Introduction

When I made a copy site of flea market, I had a hard time because I made the structure a little difficult, so I decided to keep it as a record. If you have any suggestions, such as making it more beautiful, please.

Implementation method

Development environment

Premise

--devise is already installed --The login function in the default state of devise has been implemented. --Transition from page 1 → page 2 → top page (login) --There are three tables, ʻusers profiles`` sending_destinations. --The first page deals with both ʻUser model and Profile model in one form.

DB design

users table

Column Type Options
name string null: false, unique: true, index:true
email string null: false, unique: true, index:true
password string null: false

profiles table

Column Type Options
first_name string null: false
family_name string null: false
first_name_kana string null: false
family_name_kana string null: false
introduction string null: true
year integer null: false
month integer null: false
day integer null: false

sending_destinations (address) table

Column Type Options
first_name string null :false
family_name string null: false
first_name_kana string null: false
family_name_kana string null: false
post_code string null: false
prefecture string null: false
city string null:false
house_number string null: false
building_name string -
phone_number string unique: true, null: true
user_id references null: false, foreign_key: true

code

Creating a controller

--Create a ʻusers` controller under devise management

Terminal


$ rails g devise:controllers users

--Set the routing to refer to which controller

routes.rb


Rails.application.routes.draw do
  devise_for :users, controllers: { registrations: 'users/registrations' }
  root to: 'items#index'
end

Describe the association in the model

--Describe associations in each model of ʻUser, Profile, Sending_destination`

user.rb


class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_one :profile
  accepts_nested_attributes_for :profile
  has_one :sending_destination
end

profile.rb


class Profile < ApplicationRecord
  belongs_to :user, optional: true
end

sending_destination.rb


class SendingDestination < ApplicationRecord
  belongs_to :user, optional: true
end

ʻOptional: true` is an option that allows the foreign key to be null.

Edit the new action and the corresponding view (page 1)

--Write a new action in users / registrations_controller.rb

users/registrations_controller.rb


class Users::RegistrationsController < Devise::RegistrationsController
  #abridgement
  def new
    @user = User.new
    @user.build_profile
  end 
  #abridgement
end
 

--Edit registrations / new.html.haml corresponding to new action

ruby:devise/registrations/new.haml.html


= form_for(@user, url: user_registration_path) do |f|
  = render "devise/shared/error_messages", resource: @user
  = f.text_field :nickname
  = f.email_field :email
  = f.password_field :password
  = f.password_field :password_confirmation
  = f.fields_for :profile do |p|
    = p.text_field :family_name
    = p.text_field :first_name
    = p.text_field :family_name_kana
    = p.text_field :first_name_kana
    = p.select :year
    = p.select :month
    = p.select :day
  = f.submit "next"

Actually, there are descriptions of div, label, and class, but they are written simply. We are using fields_for to handle the two models. I refer to the following articles. [Rails] How to send values to two models at the same time with devise form (example: User model and Profile model) [Rails] How to register data to multiple models with one form_for

edit create action

--Validation check of the information entered on the first page --Have the information entered on page 1 in session --Create an instance to be used for the next address information registration and transition to the relevant page The above three points will be done by the create action.

users/registrations_controller.rb


class Users::RegistrationsController < Devise::RegistrationsController
  #abridgement
  def create
    @user = User.new(sign_up_params)
    @user.build_profile(sign_up_params[:profile_attributes])
    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]
    session[:profile_attributes] = sign_up_params[:profile_attributes]
    @sending_destination = @user.build_sending_destination
    render :new_sending_destination
  end
  #abridgement
  protected
  #abridgement
end

Check if the parameter violates validation with the valid? method. The function session that keeps the information on the client side is used so that the information does not disappear even if the page changes. The data is formatted using the attributes method so that the session holds the information in the form of a hash object. Also, although the password information is included in the params, the password information is not included when the data is formatted by the attributes method. So you need to assign the password to session again. Create an instance of the sending_destination model associated with the instance @ user created this time with build_sending_destination. Then render to the view of the new_sending_destination action that displays the page to register the address information.

Edit the new_sending_destination action and the corresponding view (page 2)

--Routing settings for the new_sending_destination action that displays the address registration page --Routing settings for the create_sending_destination action to register an address

routes.rb


Rails.application.routes.draw do
  devise_for :users, controllers: { registrations: 'users/registrations' }
  devise_scope :user do
    get 'sending_destinations', to: 'users/registrations#new_sending_destination'
    post 'sending_destinations', to: 'users/registrations#create_sending_destination'
  end

  root to: 'items#index'
end

--Create the corresponding view file new_sending_destination.html.haml

ruby:devise/registrations/new_sending_destination.html.haml


= form_for @sending_destination do |f|
  = render "devise/shared/error_messages", resource: @sending_destination
  = f.text_field :family_name
  = f.text_field :first_name
  = f.text_field :family_name_kana
  = f.text_field :first_name_kana
  = f.text_field :post_code
  = f.text_field :prefecture
  = f.text_field :city
  = f.text_field :house_number
  = f.text_field :building_name
  = f.number_field :phone_number
  = f.submit "sign up"  

edit the create_sending_destination action

--Validation check of the address information entered on the second page --Save as user information together with the information that validation check is completed and the information that was held in session. --Delete session --Log in

users/registrations_controller.rb


class Users::RegistrationsController < Devise::RegistrationsController
  #abridgement
  def create_sending_destination
    @user = User.new(session["devise.regist_data"]["user"])
    @profile = @user.build_profile(session[:profile_attributes])
    @sending_destination = SendingDestination.new(sending_destination_params)
    unless @sending_destination.valid?
      flash.now[:alert] = @sending_destination.errors.full_messages
      render :new_sending_destination and return
    end
    @user.build_sending_destination(@sending_destination.attributes)
    @user.save
    @profile.save
    session["devise.regist_data"]["user"].clear
    session[:profile_attributes].clear
    sign_in(:user, @user)

    redirect_to root_path
  end

  protected

  def sending_destination_params
    params.require(:sending_destination).permit(
      :first_name,
      :family_name,
      :first_name_kana, 
      :family_name_kana, 
      :post_code, 
      :prefecture, :city, 
      :house_number, 
      :building_name, 
      :phone_number
    )
  end
end

The information held in session is assigned to each instance of @ user and @ prfile. Check the address information on the second page with valid?. Substitute the params sent using build_sending_destination into @ user that contains the held session. Then save it to the table using the save method. Delete session using the clear method. Log in with sign_in (: user, @user) and move to the top page with redirect_to root_path.

in conclusion

It can be implemented by the above method. By using fields_for on the first page, I had a lot of trouble assigning to session, but thanks to that, I was able to think about the mechanism etc. firmly. I haven't explained it in detail, but I tried to write an article that also serves as an output, so I hope it will be helpful as much as possible.

Recommended Posts

[Rails] Implementation of new registration function in wizard format using devise
Implementation of user authentication function using devise (2)
Implementation of user authentication function using devise (1)
Implementation of user authentication function using devise (3)
[Rails 6] Implementation of new registration function by SNS authentication (Facebook, Google)
[Rails] Implementation of search function using gem's ransack
[Rails 6] Implementation of inquiry function using Action Mailer
Create authentication function in Rails application using devise
[Rails] Implementation of image enlargement function using lightbox2
[Rails] Implementation of retweet function in SNS application
[Note] Summary of rails login function using devise ①
Implementation of Ruby on Rails login function (devise edition)
[Rails 6] Implementation of search function
[Rails] Implementation of multi-layer category function using ancestry "Preparation"
[Rails] Implementation of category function
[Rails] Implementation of multi-layer category function using ancestry "seed"
[Rails] Implementation of tutorial function
[Rails] Implementation of like function
[Rails] Implementation of multi-layer category function using ancestry "Editing form"
[Rails] Implementation of multi-layer category function using ancestry "Creation form"
Rails sorting function implementation (displayed in order of number of like)
[Rails] Implementation of tagging function using intermediate table (without Gem)
Implement user registration function and corporate registration function separately in Rails devise
[Rails] Implementation of CSV import function
[Rails] Asynchronous implementation of like function
[rails] Login screen implementation in devise
[Rails] Implementation of image preview function
[Rails] About implementation of like function
[Rails] Implementation of user withdrawal function
[Rails] Implementation of CSV export function
Implementation of like function in Java
[Implementation procedure] Create a user authentication function using sorcery in Rails
[Rails] Sign-up function using devise error number of arguments (given 0, expected 1)
[Rails] Implementation of coupon function (with automatic deletion function using batch processing)
[Rails] Implementation of tag function using acts-as-taggable-on and tag input completion function using tag-it
[rails6.0.0] How to save images using Active Storage in wizard format
[Rails] Function restrictions in devise (login / logout)
Rails [For beginners] Implementation of comment function
[Rails 6] Implementation of SNS (Twitter) sharing function
[Vue.js] Implementation of menu function Implementation version rails6
[Ruby on rails] Implementation of like function
[Vue.js] Implementation of menu function Vue.js introduction rails6
[Rails] I will explain the implementation procedure of the follow function using form_with.
Implementation of Ruby on Rails login function (Session)
Implement star rating function using Raty in Rails6
[Rails] Implementation of "notify notification in some way"
[Rails] Implementation of batch processing using whenever (gem)
[Rails] Implementation of PV number ranking using impressionist
[Rails] Implementation of image slide show using Bootstrap 3
[Rails 6] Change redirect destination at the time of new registration / login by devise
[Rails / devise] Implementation of account information editing function / Procedure for changing redirect destination
[Rails] Set validation for the search function using Rakuten API (from the implementation of Rakuten API)
Ruby on Rails <2021> Implementation of simple login function (form_with)
[Rails] Implementation of drag and drop function (with effect)
[Rails] Test of star evaluation function using Raty [Rspec]
[Rails] Implement credit card registration / deletion function in PAY.JP
Implementation of search function
[Ruby on Rails] Implementation of tagging function/tag filtering function
Rails search function implementation
Implementation of pagination function
[Rails] Implementation of SNS authentication (Twitter, Facebook, Google) function