Help us understand the problem. What is going on with this article?

[Rails]paranoiaを使わずに退会機能を実装する(ユーザーを論理削除する)

実装すること

paranoiaを使わずに、ユーザーの退会機能を作成するために下記のコードを書いていきます。
①ユーザーを論理削除する。
②退会ユーザーをログアウトさせる。
③退会ユーザーはログインできなくする。

ページ設計

マイページ(users/show.html.erb)で退会できるようにします。

Userテーブル定義

is_deletedカラムを作成し、デフォルトをfalseにしておきます。
退会ユーザーのis_deletedをtrueにすることで退会ユーザーのデータは残したまま、退会しているかどうかを区別できるようにします。

カラム名 カラム説明 データ型 デフォルト
ID ユーザーID integer
name ユーザー名 string
is_deleted 削除フラグ datetime FALASE
created_at 登録日 datetime NOW
updated_at 更新日 boolean NOW

Userモデルの作成

Userモデルはdeviseを使用してモデルを作成していきます。

deviseの導入・Userモデルの作成

Gemfile.
gem 'devise'
$ bundle install
$ rails g devise:install
$ rails g devise user name:string is_deleted:boolean
$ rails g devise:views

コントローラの作成・編集

$ rails g controller users

users_controller.rb

hideアクションを作成します。
@user.update(is_deleted: true)で、@userのis_deletedカラムをtrueにupdateします。
reset_sessionで、ユーザーをログアウトさせます。
redirect_to root_pathで、ログアウト後ルートパスに飛ばします。

app/controllers/users_controller.rb
    def show
        @user = User.find(params[:id])
    end

    def hide
        @user = User.find(params[:id])
        #is_deletedカラムにフラグを立てる(defaultはfalse)
        @user.update(is_deleted: true)
        #ログアウトさせる
        reset_session
        flash[:notice] = "ありがとうございました。またのご利用を心よりお待ちしております。"
        redirect_to root_path
    end

ルーティングの作成

hideアクションのルーティングを作成します。
as: 'users_hide'で、showアクションと間違われないようURL名を指定します。

config/routes.rb
Rails.application.routes.draw do

  devise_for :users

  resources :users
  put "/users/:id/hide" => "users#hide", as: 'users_hide'
end

退会ボタンの作成

マイページ(users/show.html.erb)

if user_signed_in? && @user.id == current_user.idで、ユーザーがログインしていて且つログインユーザーであれば退会ボタンを表示するようにしています。
"data-confirm" => "本当に退会しますか?"で退会ボタンクリック時にアラートが出るようにしています。

app/views/users/show.html
<% if user_signed_in? && @user.id == current_user.id %>
        <%= link_to "退会", users_hide_path(current_user), method: :put, "data-confirm" => "本当に退会しますか?", class: "btn btn-outline-danger" %>
<% end %>

退会ユーザーはログインできなくする

user.rb

ログインする時に退会済み(is_deleted==true)のユーザーを弾くためのメソッドを作成します。
super && (self.is_deleted == false)で、userのis_deletedがfalseならtrueを返すようにしています。

app/models/user.rb
class User < ApplicationRecord

  def active_for_authentication?
    super && (self.is_deleted == false)
  end

end

sessions_controller.rb

if (@user.valid_password?(params[:user][:password])で、入力されたパスワードが正しいことを確認しています。
(@user.active_for_authentication? == false))で、@userのactive_for_authentication?メソッドがfalseであるかどうかを確認しています。
・上記の2点が当てはまれば、ログインページにリダイレクトし、エラーメッセージを表示するようにしています。

app/controllers/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController

  before_action :reject_user, only: [:create]

  protected

  def reject_user
    @user = User.find_by(email: params[:user][:email].downcase)
    if @user
      if (@user.valid_password?(params[:user][:password]) && (@user.active_for_authentication? == false))
        flash[:error] = "退会済みです。"
        redirect_to new_user_session_path
      end
    else
      flash[:error] = "必須項目を入力してください。"
    end
  end
end

sessions/new.html.erb

エラーメッセージを表示するため、<%= flash[:error] %>をお好きなところに追記してください。

app/views/sessions/new.html
<%= flash[:error] %>

最後に

最後までご覧いただきありがとうございます。
初学者ですので間違っていたり、分かりづらい部分もあるかと思います。
何かお気付きの点がございましたら、お気軽にコメントいただけると幸いです。
twitter:https://twitter.com/yto_oct
note:https://note.com/yto_oty

参考

特定のユーザのアカウントは残しつつ、ログインできないようにしたい
https://blog.edwardkenfox.com/post/90435229476/%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%AE%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%81%AF%E6%AE%8B%E3%81%97%E3%81%A4%E3%81%A4%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%97%E3%81%9F%E3%81%84

RailsでDeviseを使っていて、入力されたパスワードが正しいかどうかを自前で実装したい場合
https://qiita.com/knt45/items/49f8ad2bdef906dca302

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした