0
0

More than 3 years have passed since last update.

deviseを用いたユーザー登録をウィザード形式にする

Posted at

備忘録として書き込みます

環境

  • ruby 2.5.1
  • Rails 5.2.4.1
  • devise (4.7.1)

一つのアカウントで複数人の栄養管理をするという趣旨アプリを作っています。
また、アカウント登録と同時に管理ユーザーも一人登録するという想定でアプリを作っています。
そのためにウィザード形式での登録を使ったらカッコ良いんじゃないかなあと思い使ってみました。

まず、deviseを使ってUserモデルを登録(アカウントに当たります)

db/migrate

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string :name, null: false

   #略

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

     #略

      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true

end

そして、Userに紐づいたPersonです(管理ユーザーに当たります)

db/migrate

class CreatePeople < ActiveRecord::Migration[5.2]
  def change
    create_table :people do |t|
      t.string :name, null: false
      t.float :height, null: false
      t.float :weight, null:false
      t.string :gender, null: false

      t.timestamps
    end
  end
end

ここには書きませんがUserとPersonはUser1の一対多のアソシエーションを組んでいます。

作業

ここからが本題です。
まず、見えていなかったdeviseのコントローラーを呼び出します

ターミナル
rails g devise:controllers users

次にルーティングでコントローラーをいじれるようにして、
deviseに新しいアクションを設定します

config/route.rb
#usersで遷移するようにする
devise_for :users, controllers: {
    registrations: 'users/registrations',
  }
#アクション2つ作成
devise_scope :user do
    get 'new_first_person', to: 'users/registrations#new_first_person'
    post 'create_first_person', to: 'users/registrations#create_first_person'
end

こうすることでルーティングが、
devise/registrations#○○○

users/registrations#○○○
とカスタマイズすることができます。
こうしないとUser.newをモデルに引き込んでいるformがregistrationコントローラーのアクションに飛んでくれません

ビューのコードです。
僕はこんな感じです。
やったこととしてはform_forのresourceの部分を@user(User.new)にしたりurlを変えたぐらいです

views/users/registrations/new.html.haml

.form
  %h1.form__title 新しいアカウントを作成
  = form_for(@user, url: user_registration_path) do |f|
    = render "devise/shared/error_messages", resource: resource
    .field
      = f.text_field :name,placeholder: "アカウント名", autofocus: true, autocomplete: "email",class:"field--form"
    .field
      = f.email_field :email,placeholder: "メールアドレス", autofocus: true, autocomplete: "email",class:"field--form"
    .field
      = f.password_field :password,placeholder: "パスワード(半角英数字6文字以上)", autocomplete: "new-password",class:"field--form"
    .field
      = f.password_field :password_confirmation,placeholder: "パスワード(確認)", autocomplete: "new-password",class:"field--form"
    .actions
      = f.submit "新しいアカウントを作成",class: "form--submit"

もう一つ、renderで出す方のビューです

views/users/resistrations/new_first_person.html.haml

.form_header
  .form_header--title
    =link_to "CARE KITCHEN","#"
  .form_header--icon
    =link_to new_user_session_path do
      %i.fas.fa-door-open
      %p ログイン


.form
  %h1.form__title 一人目のユーザー登録
  = form_for(@person, url: create_first_person_path) do |f|
    -# = render "devise/shared/error_messages", resource: resource
    .field
      = f.text_field :name,placeholder: "ユーザー名", autofocus: true,class:"field--form"

    .field.birthday
      = f.date_field :birthday,placeholder: "生年月日", autofocus: true,class:"birthday__form"
      %p.birthday__title 生年月日

    .field
      = f.select :gender,[["性別を選択してください",""],["男性","0"],["女性","1"]],class: "select_gender"
    .field
      = f.number_field :height,placeholder: "身長(m) 例:165.5kg",class:"field--form",step: "0.1"
    .field
      = f.number_field :weight,placeholder: "体重(kg) 例:55.5kg",class:"field--form",step: "0.1"
    .actions
      = f.submit "入力完了",class: "form--submit"
  -# = render "users/shared/links"

ここでコントローラーを弄ります

app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController

  #略

  def new
    @user = User.new
  end


  def create
    @user = User.new(sign_up_params)
    unless @user.valid?
      flash.now[:alert] = @user.errors.full_messages
      render :new
    end
    session["create_acount"] = { user: @user.attributes}
    session["create_acount"][:user]["password"] = params[:user][:password] 
    @person = @user.people.build
    render :new_first_person
  end

  def create_first_person
    @user = User.new(session["create_acount"]["user"])
    @person = Person.new(person_params)
    unless @person.valid?
      flash.now[:alert] = @address.errors.full_messages
      render :new_first_person and return
    end
    @user.people.build(@person.attributes)
    @user.save
    @person[:user_id] = @user.id
    sign_in(:user, @user)
    redirect_to root_path
  end

  #略


  protected


  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
  end

  def person_params
    params.require(:person).permit(:name,:birthday,:gender,:height,:weight)
  end

 #略

end


上から順に話します

①newアクション
ここでUserのインスタンスを作成

②createアクション
ストロングパラメータで値を受け取り@userに代入します
@userの検証を行い、問題がなかったら"create_acount"と名付けたsessionという箱に"user"のデータを入れます
ここで気をつけたいのがpasswordはこの時sessionに代入されない点です
改めてsessionに入れてあげます
で、@userに紐づいたpersonのインスタンスを生成し、new_first_personのビューをrenderします

③create_first_person
ひとまずsessionに入れておいたuserの情報からUserインスタンスを作ります
personはフォームから送られた情報です
personの検証を行い保存です

まとめ

sessionに情報を入れてアクションをまたいで保存、っていうイメージなんですかね?
勉強になりました。
間違っていることがあれば指摘していただけると助かります

0
0
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
0