[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] %>
```

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

## 参考
特定のユーザのアカウントは残しつつ、ログインできないようにしたい
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