「rails6 論理削除 実装」と調べたあなたへ



## はじめに

今現在、私はとあるプログラミングスクールにて日々奮闘中の身でございます。　
きっといま、あなたは何かしらの開発の段階で論理削除という言葉を知り、実装方法を
模索していることかと思います。

かくいう私も、現在プログラミング学習の毎日で、なにかすばらしいスキルをや機能を
ご紹介できると言われるとまだまだです。ですのでこれは自分自身の備忘録も兼ねております。
よってまだまだ未熟のため間違っている点や不適切な表現があるかもしれませんがご容赦
いただきたいと共に、なにかご助言をいただければ幸いです。

とはいえ、あなたのお困りごとのなにか一助になれれば幸いと思いこの記事を
書くことにしました。

## 前提条件

・deviseを用いての何かしらの開発経験がある方
・論理削除の一例を知りたい方
・論理削除のためのgem（ [`paranoia`](https://github.com/rubysherpas/paranoia)や[`discard`](https://github.com/jhawthorn/discard)など）を使用しない方法を知りたい方
（また、今回の論理削除は何かしらのECサイトを例に記述しています。）

## 開発環境

ruby 2.6.3
Rails 6.1.4.6

## 実装方法

### deviseをインストールして初期設定を行う

ますは準備段階として何かしたのアプリを作成し、deviseのインストールから初期設定をしましょう。
そして`rails g devise User`を実行し、必要なカラムやデータ型を記述しましょう。
その後、以下の部分を追記し、`rails db:migrate`をしましょう。
```db/migrate/2020......devise_create_users.rb
# 中略
      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      t.boolean :is_deleted, null: false, default: "false" # ここに追加したよ！！！！！！！
      t.timestamps null: false
# 中略
```
ここの記述では`is_deleted`というカラムに`boolean`というデータ型でデータを持たせ、初期値で`false`という値を持たせるというものです。

これで新規でユーザー登録をする際、`is_deleted`というカラムに`false`という値を自動的に保存させることができます。

### booleanとは

ここまで学習された方であれば、`string`や`text`などというデータ型はご存知かと思います。
`boolean`というのは簡単に説明すると`true(真)`もしくは`false(偽)`という限定的なデータの持たせ方です。
詳しくはこちらをご覧ください。[booleanとは](https://techacademy.jp/magazine/42560)

### Routingの編集

ルーティングを編集していきます。ここから先はそれぞれの実装内容によって変わりますので適宜変更してください。
まずは下記を追記します。
```config/routes.rb
# 中略
      
      patch "users/withdraw" => "users#withdraw" # ここに追加したよ！！！！！！！
      #今回はidを付与しません。ECサイトなのでcurrent_userで退会するユーザーを指定できます。
# 中略
```

### Controllerの編集

続いてコントローラーの編集をしていきます。ここで`is_deleted`カラムの値を`true`に更新します。
下記のように記述しましょう。
```app/controllers/users_controller.rb
# 中略
      #退会確認画面用のアクション
      def unsubscribe
       @user=current_customer
      end

      #退会のアクション
      def withdraw
       @user=current_customer
       @user.update(is_deleted: true) #ここでis_deletedカラムの値をtrueに更新します。
       reset_session #この記述で現在のログイン状況をリセットすることができます。
       flash[:notice] = "退会が完了しました。" #フラッシュメッセージがあると親切ですね！
       redirect_to root_path #処理完了後ルートパスへ遷移します。
      end
# 中略
```

続いてsessionsコントローラーを編集していきます。
ここで退会した後のログインを制限する記述をしていきます。
下記のようにしましょう。
```rb:app/controllers/users/sessions_controller.rb
class Users::SessionsController < Devise::SessionsController
  before_action :reject_deleted_user, only: [:create]

  # 中略

  def reject_deleted_user
    @user=User.find_by(email: params[:user][:email])
    if @user
      if @user.valid_password?(params[:user][:password]) && @user.is_deleted == true
        flash[:notice] = "退会済みの為、再登録が必要です。"
        redirect_to new_customer_registration_path
      end
    end
  end
end
```

ここの記述は理解しづらい部分かもしれません。
まずは
```
before_action :reject_deleted_user, only: [:create]
```
`before_action`の部分で`only: [:create]`と指定することでログインが処理がされる前に
`reject_deleted_user`メソッドが実行されます。
このメソッドの中身を見ていきましょう。
```
@user=User.find_by(email: params[:user][:email])
```
このように記述するこで入力されたemailをユーザーテーブルから探し出してきます。
そして探したものを`@user`に代入しています。
続いて
```
    if @user
      if @user.valid_password?(params[:user][:password]) && @user.is_deleted == true
        flash[:notice] = "退会済みの為、再登録が必要です。"
        redirect_to new_user_registration_path
      end
    end
```

`valid_password?`とは、特定のアカウントのパスワードと入力されたパスワードが一致しているかを確認するためのDevise が用意しているメソッドです。
今回の場合は、find_by メソッドで特定したアカウントのパスワードとログイン画面で入力されたパスワードが一致しているかを確認する用途で使用します。
ここでの記述を要約すると、「入力したメールアドレスが一緒で、かつパスワードも一緒で、かつis_deletedのカラムがtrueだったらログインさせずに新規会員登録画面に遷移させます」ということになります。
ここまでで今回の論理削除の大きいところは終了しました！！

### viewの編集

最後にビューの編集をしていきましょう。
下記のように編集していきます。
```app/views/public/customers/unsubscribe.html.erb
<div class="container text-center">
  <div class="row">
    <div class="col-8 mx-auto">
      <h1 class="my-5"><strong>本当に退会しますか？</strong></h1>
      <div>
        <span><strong>退会すると、会員登録情報や</strong></span></br>
        <span><strong>これまでの購入履歴が閲覧できなくなります。</strong></span></br>
        <span><strong>退会する場合は、「退会する」をクリックしてください。</strong></span>
      </div>
    </div>
  </div>

  <div class="row mt-5 d-flex justify-content-center">
    <div class="col-2">
      <%= link_to "退会しない", customers_my_page_path, class: "btn btn-primary btn-block btn-sm"%>
    </div>
    <div class="col-2">
      <%= link_to "退会する", customers_withdraw_path, method: :patch, class: "btn btn-danger btn-block btn-sm"%>
    </div>
  </div>
</div>

```

## まとめ

お疲れさまでした！！
自分自身初めての実装でわからないことだらけでした。最初はなんとなく全体の理解をしてから、ひとつひとつ深堀りして進めていけば必ず力になると思います。
まだまだ学習中のみで、なおかつ初投稿ということもあり、分かりにくい表現等もあったかと思いますがその際はご指摘いただければ幸いです。