2
6

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 3 years have passed since last update.

[セッション実装]ユーザー登録(APIの続編)

Last updated at Posted at 2020-01-05

##チーム課題を個人でやってみるけん_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モデルとのリレーションを記述
※必要に応じてカラムの内容は変更してください

xxxxxxxxxx_create_addresses.rb
#変更前
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のあたいは数字で入力します。

app/models/address.rb
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モデルについてもアソシエーションを設定

app/models/user.rb
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アクションと対応するビューを編集

app/controllers/users/registrations_controller.rb
#編集前
# GET /resource/sign_up
  # def new
  #   super
  # end

#編集後
  # GET /resource/sign_up
  def new
    super
  end

newアクションに対応するフォームの修正

app/views/devise/registrations/new.html.erb
#修正前
= f.submit "Sign up"
#修正後
= f.submit "Next"

##createアクションを編集
バリデーションチェック
セッション保持
住所情報登録で使用するインスタンスを生成、当該ページへ遷移

app/controllers/users/registrations_controller.rb
#変更前
  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アクションのルーティングも設定

config/routes.rb
#変更前
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
app/views/devise/registrations/new_address.html.haml
%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アクションと対応するビューを編集

app/controllers/users/registrations_controller.rb
#変更前
    #バリデーションチェック
    @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に対応するビューを作成

app/views/devise/registrations/create_address.html.haml
%h2登録が完了しました
= link_to "トップへ戻る", root_path

##参考

####devise_scopeに関する記事

##終わりに
ビューを整えることなど細々した修正は必要ですがセッションとAPIのサーバーサイド実装完了です。
作り始めの時に
registrations_controller.rbでunless @user.valid?という記述の下にパスワード自動生成のコードを記述していました。
valid?の時点でパスがないので全て弾かれパス生成する箇所が読み込まれていないことに気づくのにひどく時間がかかってしまい苦しみました。。。
(早くbinding.pry使えばよかった(>_<))

バリデーションなどの記載がまだまだ
不十分+日本語化していないのでその辺もちょくちょく修正していければと思います。
不備やアドバイス等ございましたらお知らせいただければ幸いです。

2
6
1

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
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?