🌟
[Rails]退会機能
モデル
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
# 退会処理・退会したユーザーはログインできない
def active_for_authentication?
super && is_active != false
end
def inactive_message
is_active == false ? :inactive_account : super
end
end
devise :database_authenticatable, :registerable,:recoverable, :rememberable, :validatable
これは Deviseに「どんな機能を使うか」伝える宣言。
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
これを書くことで、「このUserモデルにはDeviseのこれらの機能を使いたいです!」と指定している。
モジュール名 | 何をしてくれる? |
---|---|
:database_authenticatable |
パスワードによるログイン機能(DBで認証) |
:registerable |
サインアップ機能(新規登録・編集・削除) |
:recoverable |
パスワード忘れたときの再設定機能(メールで送信) |
:rememberable |
「ログイン状態を保持する」(remember me) |
:validatable |
メール形式・パスワードのバリデーションを自動でやってくれる |
active_for_authentication?
def active_for_authentication?
super && is_active != false
end
active_for_authentication?
active_for_authentication?
はDeviseに元からあるメソッドで、認証が有効かどうかを確認する。
super
super
は、「親クラスの同じ名前のメソッドを呼び出す」というRubyの機能。
この場合の親とは…?
active_for_authentication?
メソッドは、元々は Devise::Models::Authenticatable
というモジュールに定義されている。
devise/lib/devise/models/authenticatable.rb
def active_for_authentication?
true
end
inactive_message
Deviseがログイン失敗時に 「なぜログインできなかったのか?」 を伝えるために使うメソッド。
def inactive_message
is_active == false ? :inactive_account : super
end
流れ
- ログインしようとする
-
active_for_authentication?
で「ログインできるか?」を判定 - もし
false
が返ってきたら… - Deviseは
inactive_message
を呼び出して「どんな理由でログインできなかったのか?」を取得 - 画面にその理由に応じたエラーメッセージを表示する
config/locales/devise.ja.yml
inactive_account
でエラーメッセージを出力する。
ja:
devise:
failure:
inactive_account: "退会済みのアカウントです。再度ご登録ください。"
ユーザーをすでに登録済で途中から退会機能を追加した場合の処理
true
にする)
登録済ユーザーの退会状態を変更する(すべて rails console
# ユーザーの `is_active` カラムの状態を確認する
User.pluck(:id, :is_active)
# 既存データの `is_active` カラムをすべて `true` にする
User.where(is_active: nil).update_all(is_active: true)
is_active
カラムの初期値を true
にする
すでにカラムがあって後から変更する場合
rails generate migration ChangeDefaultIsActiveOnUsers
できたマイグレーションファイルを以下に変更する。
class ChangeDefaultIsActiveOnUsers < ActiveRecord::Migration[6.1]
def change
change_column_default :users, :is_active, from: nil, to: true
end
end
rails db:migrate
カラムを新規に追加する場合
rails generate migration AddIsActiveToUsers is_active:boolean
できたマイグレーションファイルを以下に変更する。
class AddIsActiveToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :is_active, :boolean, default: true
end
end
rails db:migrate
コントローラー
users_controller.rb
# 退会済のユーザーは一覧に表示しない
def index
@users = User.where(is_active: true).page(params[:page])
end
# 退会アクション
def withdraw
@user = User.find(params[:id])
if @user == current_user
# 退会状態に更新
@user.update(is_active: false)
# セッションをリセットしてログアウト
reset_session
redirect_to new_user_registration_path, notice: "退会処理が完了しました。ご利用ありがとうございました。"
else
redirect_to user_path(@user), alert: "不正な操作です。"
end
end
@users = User.where(is_active: true).page(params[:page])
def index
@users = User.where(is_active: true).page(params[:page])
end
User.where(is_active: true)
① -
User
モデルから 「退会していないユーザー」だけを抽出する。 -
is_active
がtrue
のユーザーだけが対象。-
is_active == false
→ 退会済み -
is_active == true
→ アクティブ(表示対象)
-
.page(params[:page])
② - これは ページネーション(ページ分割)のための処理。(
kaminari
を使用) -
params[:page]
には「今表示したいページ番号」が入る。
つまりこの行で
- アクティブなユーザーだけを取得して
- ページに分けて
-
@users
に代入して - ビューで一覧表示できる状態にしている
tasks_controller.rb
# アクティブユーザーのタスクのみ表示
def index
@tasks = Task.joins(:user).where(users: { is_active: true }).page(params[:page])
end
Task.joins(:user)
- Task モデルが User に belongs_to :user している前提
- joins(:user) は 「タスクとユーザーを結びつけて一緒に検索する」ためのSQL JOIN(内部結合)を意味する
- タスクにひもづいたユーザーの情報も一緒に見ながら絞り込みたい
SELECT * FROM tasks INNER JOIN users ON tasks.user_id = users.id WHERE users.is_active = true;
- タスクにひもづいたユーザーの情報も一緒に見ながら絞り込みたい
.where(users: { is_active: true })
- 結合したユーザーの中から、is_active が true の人だけを対象にする。
- つまり、「退会してないユーザーが作ったタスクだけ」を取得
ビュー
users/show.html.erb
<% if @user == current_user %>
<%= link_to "退会", withdraw_user_path(@user), method: :patch, data: { confirm: "本当に退会しますか?" } %>
<% end %>
参考文献
Discussion