[初心者]Gem『paranoia』を用いたユーザー管理をやってみた

#前提
deviseを用いた会員登録機能実装済み
管理者機能実装済み
https://qiita.com/NZTK/items/7868b2897ff1c46ee338
(管理者機能追加)
#環境
Ruby2.5.5
Rails 5.2.3

使用gem

- devise
- paranoia

https://github.com/rubysherpas/paranoia

#準備

####gemの導入
```ruby:Gemfile
gem 'paranoia'
```
```
$bundle install
```
####カラム編集
```
rails g migration AddColumnToUsers deleted_at: datetime
```
```ruby:xxx_add_column_to_users
class AddColumnToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :deleted_at, :datetime
  end
end
```
####モデル編集
```ruby:user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  acts_as_paranoid #追加
end
```
これで論理削除ができるようになりました。
#確認
`rails  c`を実行し、ユーザーが正しく論理削除できているか確認してみます。

```ruby
User.find(1)
 User Load (8.8ms)  SELECT  "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
+----+---------+-----------------------+----------------------+------------------------+---------------------+-----------------------+------------------------+--------+------------+
| id | email   | encrypted_password    | reset_password_token | reset_password_sent_at | remember_created_at | created_at            | updated_at             |  admin | deleted_at |
+----+---------+-----------------------+----------------------+------------------------+---------------------+-----------------------+------------------------+--------+------------+
| 1  | 1@1.com | $2a$11$C146AIA186C... |                      |                        |                     | 2019-07-10 05:40:5... | 2019-07-16 06:27:09... |  false |            |
+----+---------+-----------------------+----------------------+------------------------+---------------------+-----------------------+------------------------+--------+------------+

User.find(1).destroy
 User Load (2.5ms)  SELECT  "users".* FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 User Update (5.2ms)  UPDATE "users" SET "deleted_at" = ?, "updated_at" = ? WHERE "users"."id" = ?  [["deleted_at", "2019-07-17 14:48:44.544469"], ["updated_at", "2019-07-17 14:48:44.544500"], ["id", 1]]
   (5.3ms)  commit transaction
+----+---------+-----------------------+----------------------+------------------------+---------------------+-----------------------+------------------------+--------+--------------------+
| id | email   | encrypted_password    | reset_password_token | reset_password_sent_at | remember_created_at | created_at            | updated_at             |  admin | deleted_at         |
+----+---------+-----------------------+----------------------+------------------------+---------------------+-----------------------+------------------------+--------+--------------------+
| 1  | 1@1.com | $2a$11$C146AIA186C... |                      |                        |                     | 2019-07-10 05:40:5... | 2019-07-16 06:27:09... |  false | 2019-07-17 14:48...|
+----+---------+-----------------------+----------------------+------------------------+---------------------+-----------------------+------------------------+--------+--------------------+
```

こんな感じで`deleted_at`カラムに`User.destroy`を実行した時間が入っていれば成功です。
復活させたい場合は、`User.restore(1)`を実行すれば`deleted_at`から時刻表示が消え、ユーザーが復活しています。
削除状態では`User.all`では表示されないので、`User.with_deleted`を用いて削除されたユーザーもまとめて出力することができます。削除済みユーザーのみを出す場合は`User.only_deleted`を使います。

#ユーザー管理してみる
https://qiita.com/NZTK/items/7868b2897ff1c46ee338
この記事で作ったユーザー一覧を元に作っていきます。
管理者権限持ちユーザーのみがこのページへと飛んでこれるようになっています。

```ruby:users_controller
class UsersController < ApplicationController
  before_action user_admin, only: [:index, :user_restore]

  def index
      @users = User.with_deleted　#変更
  end

  def user_restore
      @user =  User.only_deleted.find(params[:id]).restore
      redirect_to  users_path 
  end

  private
    def user_admin
       @users = User.with_deleted　#変更
       if  current_user.admin == false
           redirect_to users_path
       else
           render action: "index"
       end
    end
end
```
`@users = User.with_deleted`により、削除済みユーザーも表示できるようにします。

```users/index.html.erb

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>メールアドレス</th>
      <th>削除/復元</th>
    </tr>
  </thead>
  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.id %></td>
　　　　 <td><%= user.email %></td>

　　　　　#ここから
        <% unless user.deleted_at? %>
          <td><%= link_to "編集",  edit_user_path(user.id) %></td>
          <td><%= link_to "アカウント削除", user, data: { confirm: "退会させますか?" }, method: :delete %></td>
        <% else %>
          <td><%= link_to "アカウント復元", user_restore_user_path(user), method: :patch %></td>
        <% end %>
　　　　　#ここまで説明します

      </tr>
    <% end %>
  </tbody>
</table>
```
```routes.rb
resourses: users do
  member do
    patch 'user_restore'
   end
end
```

`unless user.deleted_at?`で対象ユーザーの`deleted_at`カラムが`true`か`false`を調べています。今回のdeleted_atカラムは基本的にからであることを前提に考えているので、`unless`を用いています。
`deleted_at`が`false`の場合、`<td><%= link_to "編集",  edit_user_path(user.id) %></td>`と`<%= link_to "アカウント削除", user, data: { confirm: "退会させますか?" }, method: :delete %>`で編集ページへのリンクとアカウント削除用のリンクを表示させ、`true`の場合は`<%= link_to "アカウント復元", user_restore_user_path(user), method: :patch %>`でアカウント復元用のボタンを表示させています。

繰り返しの中で個別に分けられたものを変数`user`としてコントローラーにわたし、`only_deleted`で削除済みのデータから探し出したUserを`.rstore`で復元し、`users_path`で元の一覧画面に戻しています。

今回の復元処理は`deleted_at`カラムに存在する日付データを空にしてアップデートしているので、methodはpatchを用いています。




#まとめ
論理削除は便利ですが、多用するとデータベースを圧迫する恐れがあるので多用しないほうがいいかもしれません。復元が簡単にできるのはとても便利です。