

プロ太先生、Quick Mendanの認証システムが完成しました!講師も生徒も同じパターンで実装されていて、すごくスッキリしています!

素晴らしいね!どんな設計になっているのか、詳しく見てみようか。

はい!まず全体像から説明します。
統一された認証フロー
# 講師認証(AuthController)
GET /staff/login → staff_login(ログイン画面表示)
POST /staff/login → staff_authenticate(認証処理)
DELETE /staff/logout → staff_logout(ログアウト処理)
# 生徒認証(StudentsController)
GET /student/login → login(ログイン画面表示)
POST /student/login → authenticate(認証処理)
DELETE /student/logout → logout(ログアウト処理)

おお、完全に同じパターンだね!URLの構造も統一されている。
セッションベース認証の実装
講師認証の実装
# app/controllers/auth_controller.rb
class AuthController < ApplicationController
def staff_authenticate
username = params[:username]
password = params[:password]
# カスタム認証メソッドで検索
teacher = Teacher.find_for_database_authentication(email: username)
if teacher && teacher.valid_password?(password)
# セッションに講師IDを保存
session[:teacher_id] = teacher.id
redirect_to staff_dashboard_path, notice: 'ログインしました'
else
flash.now[:alert] = 'ユーザー名またはパスワードが正しくありません'
render :staff_login
end
end
def staff_logout
# セッションをクリア
session[:teacher_id] = nil
redirect_to root_path, notice: 'ログアウトしました'
end
private
def current_staff_user
@current_staff_user ||= session[:teacher_id] && Teacher.find_by(id: session[:teacher_id])
end
end
生徒認証の実装
# app/controllers/students_controller.rb
class StudentsController < ApplicationController
def authenticate
student_number = params[:student_number]
password = params[:password]
# カスタム認証メソッドで検索
student = Student.find_for_database_authentication(email: student_number)
if student && student.valid_password?(password)
# セッションに生徒IDを保存
session[:student_id] = student.id
redirect_to student_dashboard_path, notice: 'ログインしました'
else
flash.now[:alert] = '生徒番号またはパスワードが正しくありません'
render :login
end
end
def logout
# セッションをクリア
session[:student_id] = nil
redirect_to root_path, notice: 'ログアウトしました'
end
private
def current_student
@current_student ||= session[:student_id] && Student.find_by(id: session[:student_id])
end
end

講師も生徒も全く同じパターンですね!セッションに保存して、ログアウト時にクリアする。シンプルです!
モデルの統一されたカスタム認証
Teacher モデル
# app/models/teacher.rb
class Teacher < ApplicationRecord
# ユーザー名でログインするための設定
def self.find_for_database_authentication(warden_conditions)
# warden_conditions = {email: "shibaguti"}
conditions = warden_conditions.dup
if (email = conditions.delete(:email))
# emailキーで渡された値をuser_login_nameで検索
where(user_login_name: email).first
else
# emailキー以外の場合はnilを返す
nil
end
end
end
Student モデル
# app/models/student.rb
class Student < ApplicationRecord
# 生徒番号でログインするための設定
def self.find_for_database_authentication(login_conditions)
# login_conditions = {email: "2024001"}
search_conditions = login_conditions.dup
if (student_number_input = search_conditions.delete(:email))
# emailキーで渡された値をstudent_numberで検索
where(["student_number = :student_number", { student_number: student_number_input }]).first
else
# emailキー以外の場合はnilを返す
nil
end
end
end

なるほど!両方とも :email キーを受け取って、それぞれの認証フィールドで検索している。Deviseとの互換性を保ちながら、カスタム認証を実現している設計だね。
ApplicationHelper の統一設計
# app/helpers/application_helper.rb
module ApplicationHelper
# 現在ログインしている講師を取得
def current_teacher
@current_teacher ||= session[:teacher_id] && Teacher.find_by(id: session[:teacher_id])
end
# 現在ログインしている生徒を取得(講師方式と統一)
def current_student
@current_student ||= session[:student_id] && Student.find_by(id: session[:student_id])
end
# 講師がログインしているかチェック
def teacher_signed_in?
current_teacher.present?
end
# 生徒がログインしているかチェック(講師方式と統一)
def student_signed_in?
current_student.present?
end
# 管理者がログインしているかチェック
def admin_signed_in?
current_teacher&.admin?
end
# 現在のユーザーが管理者かどうか
def current_user_is_admin?
current_teacher&.admin?
end
end

ヘルパーメソッドも完全に対応しています。講師用も生徒用も同じパターンで実装されています!
認証チェックの統一
講師用認証チェック
# AuthController
before_action :require_staff, only: [:staff_dashboard]
private
def require_staff
unless current_staff_user
redirect_to staff_login_path, alert: 'ログインが必要です'
end
end
生徒用認証チェック
# StudentsController
before_action :require_student_login, only: [:dashboard]
private
def require_student_login
unless current_student
redirect_to student_login_path, alert: 'ログインが必要です'
end
end

認証チェックも同じパターンだね。必要なアクションにのみ before_action を設定して、ログインが必要な場合は適切なログインページにリダイレクトする。
フォームの統一設計
講師ログインフォーム
<!-- app/views/auth/staff_login.html.erb -->
<%= form_with url: staff_login_path, method: :post, local: true do |f| %>
<%= f.text_field :username, placeholder: "ユーザー名" %>
<%= f.password_field :password, placeholder: "パスワード" %>
<%= f.submit "ログイン" %>
<% end %>
生徒ログインフォーム
<!-- app/views/students/login.html.erb -->
<%= form_with url: student_login_path, method: :post, local: true do |f| %>
<%= f.text_field :student_number, placeholder: "生徒番号" %>
<%= f.password_field :password, placeholder: "パスワード(9999)" %>
<%= f.submit "ログイン" %>
<% end %>

フォームの構造も同じです!フィールド名だけが違って、送信先のURLも統一されたパターンです!
この設計のメリット
保守性の向上
# 同じパターンなので、理解しやすく修正しやすい
# 講師用
session[:teacher_id] = teacher.id
# 生徒用
session[:student_id] = student.id
拡張性の高さ
# 将来、管理者認証を追加する場合も同じパターン
session[:admin_id] = admin.id
def current_admin
@current_admin ||= session[:admin_id] && Admin.find_by(id: session[:admin_id])
end
Deviseへの依存排除

複雑なDevise設定に依存せず、シンプルなRailsの基本機能だけで実装している。
パフォーマンスの向上
# シンプルなセッション管理 = 高速
@current_student ||= session[:student_id] && Student.find_by(id: session[:student_id])
実際の動作フロー

実際にユーザーがログインする時の流れを確認してみましょう!
生徒ログインの場合
- ログインページアクセス: GET /student/login
- フォーム送信: POST /student/login
- StudentsController#authenticate 実行
student_number = params[:student_number] # "2024001"
student = Student.find_for_database_authentication(email: student_number)
if student && student.valid_password?(password)
session[:student_id] = student.id # セッションに保存
4. ダッシュボードにリダイレクト: GET /student/dashboard
5. 認証チェック
def current_student
@current_student ||= session[:student_id] && Student.find_by(id: session[:student_id])
end

講師ログインも全く同じ流れで、フィールド名とセッションキーが違うだけです!!
まとめ

この統一認証システムで学んだことをまとめてみます!
設計の原則
- 統一性: 同じパターンを使い回す
- シンプルさ: 複雑な機能に依存しない
- 可読性: コードが理解しやすい
- 拡張性: 新しい認証タイプを追加しやすい
- 保守性: メンテナンスが容易
技術のポイント
# 1. セッションベース認証
session[:user_id] = user.id
# 2. カスタム認証メソッド
Model.find_for_database_authentication(email: identifier)
# 3. 統一されたヘルパーメソッド
def current_user
@current_user ||= session[:user_id] && User.find_by(id: session[:user_id])
end
# 4. 一貫した認証チェック
before_action :require_authentication, only: [:protected_action]

素晴らしいまとめだね!この認証システムは、シンプルで美しく、実用的だ。Railsの基本を深く理解できる、とても良い学習材料になったね。

はい!Deviseの便利さも分かりましたが、基本から作ることでRailsの認証の仕組みがよく理解できました。ありがとうございました!