備忘録として書き込みます
環境
- ruby 2.5.1
- Rails 5.2.4.1
- devise (4.7.1)
一つのアカウントで複数人の栄養管理をするという趣旨アプリを作っています。
また、アカウント登録と同時に管理ユーザーも一人登録するという想定でアプリを作っています。
そのためにウィザード形式での登録を使ったらカッコ良いんじゃないかなあと思い使ってみました。
まず、deviseを使ってUserモデルを登録(アカウントに当たります)
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です(管理ユーザーに当たります)
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に新しいアクションを設定します
#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を変えたぐらいです
.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で出す方のビューです
.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"
ここでコントローラーを弄ります
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に情報を入れてアクションをまたいで保存、っていうイメージなんですかね?
勉強になりました。
間違っていることがあれば指摘していただけると助かります