##チーム課題を個人でやってみるけん_2
セッション編です
前のページ:API編はこちら
日本語化について
バリデーションについて
バリデーションのテストコードについて
以下はAPI編で作成すみなので飛ばします
rails new XXX -d mysql
rails db:create
Gemfile[device]記述後 rails g devise:install
ルーティング設定
rails g controller XXX
app/views/XXX/にindex.html.haml作成
rails g devise XXX
マイグレーションファイル記述後 rails db:migrate
application_controller.rb修正
app/models/user.rb修正
rails g devise:views
views/devise/registrations/new.html.haml一部追記
index修正
etc...
##deviseをカスタマイズしてウィザード形式の新規登録にする
$ rails g model address
マイグレーションファイルを設定
Userモデルとのリレーションを記述
※必要に応じてカラムの内容は変更してください
#変更前
class CreateAddresses < ActiveRecord::Migration[5.2]
def change
create_table :addresses do |t|
t.timestamps
end
end
#変更後
class CreateAddresses < ActiveRecord::Migration[5.2]
def change
create_table :addresses do |t|
t.string :address_firstname, null: false
t.string :address_lastname, null: false
t.string :address_kana_firstname, null: false
t.string :address_kana_lastname, null: false
t.string :zipcode, null: false
t.string :prefectures, null: false
t.string :municipalities, null: false
t.text :address, null: false
t.string :building
t.integer :phone_number
t.references :user
end
end
end
1/8更新
zipcodeをintegerにしていましたがstring型に変更しました
理由は111−1111と言うハイフンの入った形で郵便番号を登録したいからです。
INT型だと数字のみしか通さないのでvalidatesが永遠に通らない現象が起きてしまうためです。
ハイフンなしでいい場合はINT型のままで問題ないと思います。
$ rails db:migrate
Sequel Proなどでzipcodeカラム
やaddressカラム
、user_idカラム
が作られているのを確認。
モデルを編集し、バリデーションおよびアソシエーションを設定
1/14更新
都道府県はenumで記述するのでバリデーションのテストをするときのfactorybotのあたいは数字で入力します。
class Address < ApplicationRecord
belongs_to :user, optional: true
validates :address_firstname, :address_lastname, :prefectures, :municipalities, :address ,presence: true
validates :address_kana_firstname, :address_kana_lastname, presence: true,
# カナのみ可
format: { with: /\A([ァ-ン]|ー)+\z/, message: "is must NOT contain any other characters than alphanumerics." }
validates :postal_code,presence: true,
# 郵便番号(ハイフンあり7桁)
format: { with: /\A\d{3}-\d{4}\z/, message: "is must NOT contain any other characters than alphanumerics." }
enum prefectures:{
北海道:1,青森県:2,岩手県:3,宮城県:4,秋田県:5,山形県:6,福島県:7,
茨城県:8,栃木県:9,群馬県:10,埼玉県:11,千葉県:12,東京都:13,神奈川県:14,
新潟県:15,富山県:16,石川県:17,福井県:18,山梨県:19,長野県:20,
岐阜県:21,静岡県:22,愛知県:23,三重県:24,
滋賀県:25,京都府:26,大阪府:27,兵庫県:28,奈良県:29,和歌山県:30,
鳥取県:31,島根県:32,岡山県:33,広島県:34,山口県:35,
徳島県:36,香川県:37,愛媛県:38,高知県:39,
福岡県:40,佐賀県:41,長崎県:42,熊本県:43,大分県:44,宮崎県:45,鹿児島県:46,沖縄県:47
}
end
optional: true
は外部キーがnullであることを許可するオプション
Userモデルについてもアソシエーションを設定
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:facebook, :google_oauth2]
validates :nickname, :firstname, :lastname, :birthday, presence: true
validates :password, presence: true, length: { minimum: 7 },
# 英数字のみ可
format: { with: /\A[a-z0-9]+\z/i, message: "is must NOT contain any other characters than alphanumerics." }
validates :email, presence: true,
# 重複不可
uniqueness: { case_sensitive: false },
# 英数字のみ可,@を挟んだemailの形になっているか
format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i, message: "is must NOT contain any other characters than alphanumerics." }
validates :kana_firstname, :kana_lastname, presence: true,
# カナのみ可
format: { with: /\A([ァ-ン]|ー)+\z/, message: "is must NOT contain any other characters than alphanumerics." }
has_many :sns_credentials
has_one :address #ここを足したよ
この記述を忘れるとこんなエラーが出ちゃう。
NoMethodError (undefined method `build_address' for #<User:0x00007fba7c11bd20>):
app/controllers/users/registrations_controller.rb:25:in `create'
ルーティングやdeviceの設定はAPIの時に完了しているので飛ばします
##newアクションと対応するビューを編集
#編集前
# GET /resource/sign_up
# def new
# super
# end
#編集後
# GET /resource/sign_up
def new
super
end
newアクションに対応するフォームの修正
#修正前
= f.submit "Sign up"
#修正後
= f.submit "Next"
##createアクションを編集
バリデーションチェック
セッション保持
住所情報登録で使用するインスタンスを生成、当該ページへ遷移
#変更前
def create
if params[:sns_auth] == 'true'
#パスが自動生成される
pass = Devise.friendly_token
params[:user][:password] = pass
params[:user][:password_confirmation] = pass
end
#親モデルの同名メソッドをそのまま実行(registrations#createアクションが呼ばれる)
super
end
#変更後
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
# before_action :configure_account_update_params, only: [:update]
#省略
def create
if params[:sns_auth] == 'true'
pass = Devise.friendly_token
params[:user][:password] = pass
params[:user][:password_confirmation] = pass
end
#バリデーションチェック
@user = User.new(sign_up_params)
unless @user.valid?
flash.now[:alert] = @user.errors.full_messages
render :new and return
end
#sessionに保持させる
session["devise.regist_data"] = {user: @user.attributes}
session["devise.regist_data"][:user]["password"] = params[:user][:password]
#インスタンスを生成、当該ページへ遷移
@address = @user.build_address
render :new_address
end
# 省略
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
end
end
##new_addressアクションと対応するビューを編集
・住所情報を登録させるページを表示するnew_addressアクションのルーティング設定
・住所情報を登録するcreate_addressアクションのルーティングも設定
#変更前
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions',
omniauth_callbacks: 'users/omniauth_callbacks',
registrations: 'users/registrations'
}
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root 'users#index' # ログインor新規登録を選ぶページ
resources :users, only: :new # 新規登録方法を選ぶページ
end
#変更後
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions',
omniauth_callbacks: 'users/omniauth_callbacks',
registrations: 'users/registrations'
}
# Devise::RegistrationsControllerを継承した、Users::RegistrationsControllerを作成したイメージ
devise_scope :user do
get 'addresses', to: 'users/registrations#new_address'
post 'addresses', to: 'users/registrations#create_address'
end
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root 'users#index' # ログインor新規登録を選ぶページ
resources :users, only: :new # 新規登録方法を選ぶページ
end
%h2 住所情報登録
= form_for @address do |f|
= render "devise/shared/error_messages", resource: @address
.field
= f.label :address_firstname
%br/
= f.text_field :address_firstname
.field
= f.label :address_lastname
%br/
= f.text_field :address_lastname
.field
= f.label :address_kana_firstname
%br/
= f.text_field :address_kana_firstname
.field
= f.label :address_kana_lastname
%br/
= f.text_field :address_kana_lastname
.field
= f.label :zipcode
%br/
= f.text_field :zipcode
.field
= f.label :prefectures
%br/
= f.text_field :prefectures
.field
= f.label :municipalities
%br/
= f.text_field :municipalities
.field
= f.label :address
%br/
= f.text_field :address
.field
= f.label :building
%br/
= f.text_field :building
.field
= f.label :phone_number
%br/
= f.text_field :phone_number
.actions
= f.submit "Sign up"
= render "devise/shared/links"
##create_addressアクションと対応するビューを編集
#変更前
#バリデーションチェック
@user = User.new(sign_up_params)
unless @user.valid?
flash.now[:alert] = @user.errors.full_messages
render :new and return
end
#sessionに保持させる
session["devise.regist_data"] = {user: @user.attributes}
session["devise.regist_data"][:user]["password"] = params[:user][:password]
#インスタンスを生成、当該ページへ遷移
@address = @user.build_address
render :new_address
end
# 省略
protected
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
end
end
#createアクションの下に追記
def create_address
@user = User.new(session["devise.regist_data"]["user"])
@address = Address.new(address_params)
unless @address.valid?
flash.now[:alert] = @address.errors.full_messages
render :new_address and return
end
@user.build_address(@address.attributes)
@user.save
sign_in(:user, @user)
end
#省略
protected
def address_params
params.require(:address).permit(
:address_firstname, :address_lastname, :address_kana_firstname, :address_kana_lastname,
:zipcode, :prefectures, :municipalities, :address, :building, :phone_number
)
end
# If you have extra params to permit, append them to the sanitizer.
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
end
end
##address_createに対応するビューを作成
%h2登録が完了しました
= link_to "トップへ戻る", root_path
##参考
- ウィザード形式の登録フォームでバリデーション
- Railsのバリデーションエラーメッセージの取得
- Railsウィザード形式フォームで新規登録〜Devise+session〜
- 【Rails】Sessionの使い方について
- [Rails]ウィザードフォーム実装でfields_forを使って複数のテーブルに保存する
- session管理
- facebook認証
- 【Rails】omniauth_callbacks_controllerについて
####devise_scopeに関する記事
##終わりに
ビューを整えることなど細々した修正は必要ですがセッションとAPIのサーバーサイド実装完了です。
作り始めの時に
registrations_controller.rbでunless @user.valid?という記述の下にパスワード自動生成のコードを記述していました。
valid?の時点でパスがないので全て弾かれパス生成する箇所が読み込まれていないことに気づくのにひどく時間がかかってしまい苦しみました。。。
(早くbinding.pry使えばよかった(>_<))
バリデーションなどの記載がまだまだ
不十分+日本語化していないのでその辺もちょくちょく修正していければと思います。
不備やアドバイス等ございましたらお知らせいただければ幸いです。