ユーザー管理機能の実装
実装概要
- Deviseの導入
- ユーザー管理機能の実装
- モデルの単体テストコードを書く
1. Deviseの導入
#中略
gem 'devise'
ターミナル
% bundle install
deviseの設定ファイルを作成
ターミナル
% rails g devise:install
deviseコマンドでUserモデルを作成
ターミナル
% rails g devise user
マイグレーションファイルに下記追記
class DeviseCreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
## Database authenticatable
t.string :nickname, null: false
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
t.string :first_name, null: false
t.string :last_name, null: false
t.string :first_name_kana, null: false
t.string :last_name_kana, null: false
t.date :birth_date, null: false
#~中略
バリデーションの設定
他モデルは作成していないのでアソシエーションは記述せず
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates :nickname, presence: true
validates :first_name, presence: true, format: { with: /\A[ぁ-んァ-ヶ一-龥々ー]+\z/ }
validates :last_name, presence: true, format: { with: /\A[ぁ-んァ-ヶ一-龥々ー]+\z/ }
validates :first_name_kana, presence: true, format: { with: /\A[ァ-ヶー]+\z/ }
validates :last_name_kana, presence: true, format: { with: /\A[ァ-ヶー]+\z/ }
validates :birth_date, presence: true
end
マイグレーションを実行
ターミナル
rails db;migrate
ストロングパラメーターを使えるようにする
deviseの処理を行うコントローラーはGem内に記述されているため、編集することができない
deviseにストロングパラメーターを追加するコードは、deviseのコントローラーが編集できないため、application_controller.rbに記述
class ApplicationController < ActionController::Base
before_action :basic_auth
before_action :configure_permitted_parameters, if: :devise_controller?
private
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up,
keys: [:nickname, :first_name, :last_name, :first_name_kana, :last_name_kana, :birth_date])
end
def basic_auth
authenticate_or_request_with_http_basic do |username, password|
username == ENV['BASIC_AUTH_USER'] && password == ENV['BASIC_AUTH_PASSWORD']
end
end
end
devise用のビューを作成
ターミナル
% rails g devise:views
※最終課題はサーバーサイドを重点としたカリキュラムのためビューファイルは全て用意されている。
用意されているビューファイルに置き換える。
#~中略
<%= form_with model: @user, url: new_user_registration_path, class: 'registration-main', local: true do |f| %>
#~中略
<%= render 'shared/error_messages', model: f.object %>
#~中略
<%= f.text_area :nickname, class:"input-default", id:"nickname", placeholder:"例) furima太郎", maxlength:"40" %>
#~中略
<%= f.email_field :email, class:"input-default", id:"email", placeholder:"PC・携帯どちらでも可", autofocus: true %>
#~中略
<%= f.password_field :password, class:"input-default", id:"password", placeholder:"6文字以上の半角英数字" %>
#~中略
<%= f.password_field :password_confirmation, class:"input-default", id:"password-confirmation", placeholder:"同じパスワードを入力して下さい" %>
#~中略
<%= f.text_area :last_name, class:"input-name", id:"last-name", placeholder:"例) 山田" %>
<%= f.text_area :first_name, class:"input-name", id:"first-name", placeholder:"例) 陸太郎" %>
#~中略
<%= f.text_area :last_name_kana, class:"input-name", id:"last-name-kana", placeholder:"例) ヤマダ" %>
<%= f.text_area :first_name_kana, class:"input-name", id:"first-name-kana", placeholder:"例) リクタロウ" %>
#~中略
<div class='input-birth-wrap'>
<%= raw sprintf(
f.date_select(
:birth_date,
class:'select-birth',
id:"birth-date",
use_month_numbers: true,
prompt:'--',
start_year: 1930,
end_year: (Time.now.year - 5),
date_separator: '%s'),
"<p> 年 </p>", "<p> 月 </p>") + "<p> 日 </p>" %>
</div>
#~中略
※コードは修正部分のみを掲載。
ここで必要な情報を入力して新規登録しようとするも保存できないエラーが発生。
1.ルーティングの確認
routes.rbファイルを再度確認。
Rails.application.routes.draw do
devise_for :users
root 'items#index'
end
問題なし。
2. マイグレーションの確認
ターミナル
% rails db:migrate:status
database: furima_41457_development
Status Migration ID Migration Name
--------------------------------------------------
up 20241014085357 Devise create users
問題なし。
3. フォームの確認
#~中略
<%= form_with model: @user, url: new_user_registration_path, class: 'registration-main', local: true do |f| %>
#~中略
上記コードにて正しいパスの指定ができていなかったことが判明。
RailsでのDeviseのルーティング理解
RailsアプリケーションでDeviseを導入した際、ルーティングは非常に重要です。rails routesを実行すると、各ルートのPrefix、HTTPメソッド、URIパターン、対応するController#Actionが表示されます。これを理解するためのコツを以下に示します。
-
Prefixの確認
各ルートのPrefixは、対応するURLへのショートカットです。例えば、user_registrationというPrefixは、user_registration_pathを通じて新規登録のURLにアクセスできます。 -
HTTPメソッドの確認
各ルートの左側に表示されるHTTPメソッド(GET、POSTなど)を確認することで、そのエンドポイントが受け付けるリクエストを把握できます。 -
URIパターンとController#Actionの確認
URIパターンはリクエストするURLの形式を示し、Controller#Actionはそのルートがどのアクションに対応するかを示します。例えば、new_user_registration GET /users/sign_upは新規登録フォームを表示し、user_registration POST /usersはユーザーを作成するアクションです。
具体例
新規登録の流れ:
GET /users/sign_upで新規登録フォームを取得。
POST /usersでフォームのデータを送信し、ユーザーを作成。
コードを以下に修正
<%= form_with model: @user, url: user_registration_path, class: 'registration-main', local: true do |f| %>
ユーザーデータの保存が確認できたため、トップページのヘッダー表示部分がログイン後とログイン前で変わるように修正。
#~中略
<%# deviseを導入できたら、ログインの有無で表示が変わるように分岐しましょう%>
<% if user_signed_in? %>
<li><%= link_to current_user.nickname, "#", class: "user-nickname" %></li>
<li><%= link_to 'ログアウト', destroy_user_session_path, data: {turbo_method: :delete}, class: "logout" %></li>
<% else %>
<li><%= link_to 'ログイン', new_user_session_path, class: "login" %></li>
<li><%= link_to '新規登録', new_user_registration_path, class: "sign-up" %></li>
<%# //deviseを導入できたら、ログインの有無で表示が変わるように分岐しましょう%>
<% end %>
#~中略
ユーザー詳細ページはまだ未実装のためそのまま。
ログアウト、ログインページを表示するルートをrails routesにて確認し修正。
新規登録機能とログイン・ログアウト機能の実装が完了したので、次に新規登録・ログイン共にエラーハンドリングができるように正規表現を利用してバリデーションの修正を行なっていく。
バリデーションの設定
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i
FULL_WIDTH_REGEX = /\A[ぁ-んァ-ヶ一-龥々ー]+\z/
KATAKANA_REGEX = /\A[ァ-ヶー]+\z/
validates :nickname, presence: true
validates :password, format: { with: PASSWORD_REGEX, message: 'is invalid. Include both letters and numbers' }
validates :first_name, presence: true, format: { with: FULL_WIDTH_REGEX, message: 'is invalid. Input full-width characters' }
validates :last_name, presence: true, format: { with: FULL_WIDTH_REGEX, message: 'is invalid. Input full-width characters' }
validates :first_name_kana, presence: true,
format: { with: KATAKANA_REGEX, message: 'is invalid. Input full-width katakana characters' }
validates :last_name_kana, presence: true,
format: { with: KATAKANA_REGEX, message: 'is invalid. Input full-width katakana characters' }
validates :birth_date, presence: true
end
PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i
この正規表現は、パスワードの形式を指定するためのもの。
\A は文字列の先頭を示。
(?=.?[a-z]) は、少なくとも1つの英小文字が含まれることを要求。
(?=.?\d) は、少なくとも1つの数字が含まれることを要求。
[a-z\d]+ は、英小文字と数字のみで構成されていることを示している。
\z は文字列の終わりを示す。
i フラグは、大文字と小文字を区別しない(case-insensitive)ことを意味。
FULL_WIDTH_REGEX = /\A[ぁ-んァ-ヶ一-龥々ー]+\z/
この正規表現は、全角文字(ひらがな、カタカナ、漢字)を含む名前のバリデーションに使う。
\A は文字列の先頭を示す。
[ぁ-んァ-ヶ一-龥々ー]+ は、次の文字を1回以上含むことを示している。
ぁ-ん:ひらがな
ァ-ヶ:カタカナ
一-龥:漢字(CJK統合漢字)
々:繰り返し記号(例:「人々」など)
ー:長音符(カタカナで使用する伸ばし棒)
\z は文字列の終わりを示す。
KATAKANA_REGEX = /\A[ァ-ヶー]+\z/
この正規表現は、カタカナのみで構成された文字列をバリデーションするために使う。
\A は文字列の先頭を示す。
[ァ-ヶー]+ は、次の文字を1回以上含むことを示している。
ァ-ヶ:全角カタカナ
ー:長音符(カタカナで使用する伸ばし棒)
\z は文字列の終わりを示す。
ログイン時・未ログイン時のヘッダーの表示切り替え、新規登録・ログインページへの遷移、ログアウト機能を一通り行って問題なく動いたので、次回はモデルの単体テストコードを記述してテストを行なっていきたい。