きゃまなかのブログ

新卒5年目のWEBエンジニアです。仕事は運用メインで、空いた時間に開発しています。何故かブログを始めた次の日に会社の先輩に見つかりました。変な記事書くとダメ出し食らうので、いい記事書けるように頑張ります。

【Ruby on Rails】deleted_at を使って論理削除をしよう

概要

Rails には DB のカラム名に『created_at』『updated_at』と言う、設定しておくだけで、作成日時と更新日時を自動記録してくれる、お決まりの便利な機能が用意されています。

このカラムのデータはアプリケーション内で利用するデータと言うよりも、DB の運用管理上あると便利なデータだと思っています。

例えば、ユーザーから不具合の申告を受けた場合、不具合の発生日時や原因を突き止めやすくなります。

ただし、DB の主なデータ操作には、この他に『削除』があります。

自分は DB からデータを削除する場合は、全て論理削除で行い、物理削除は利用しません。

これは、間違えて DB からデータを削除してしまった場合に簡単に復元できるからです。

また、ユーザーから不具合の申告を受けた場合、削除したデータが残っていた方が対応しやすいケースも存在するからです。

Rails ではデフォルトで論理削除の機能は用意されていないので、今回、論理削除の導入方法をまとめました。

はじめに

物理削除と論理削除の違いを簡単に説明します。

  • 物理削除は DELETE を実行した際に、DB から完全にデータを削除することです。
  • 論理削除は DELETE を実行した際に、削除用フラグを付けて、データを削除扱いにすることです。DB にデータは残っています。

導入方法

gem の紹介

Rails で論理削除を導入するにはたくさんの gem が存在しています。

論理削除の gem で有名なものだとここら辺の名前が上がるかと思います。

github.com

github.com

github.com

論理削除は gem を利用した導入方法が一番楽だと思います。

今回は paranoia と言う gem を利用して説明します。

Gemfile に paranoia を追記してインストールしてください。

$ vim Gemfile
gem 'paranoia', '~> 2.3', '>= 2.3.1'

# インストール $ bundle install --path vendor/bundle

 ApplicationRecord に設定追加

app/models/application_record.rb に以下の設定を追記します。

$ vim app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  acts_as_paranoid # 追加
  self.abstract_class = true
end

カラムの追加

論理削除を行うには『deleted_at』と言う削除フラグ用のカラムを新しく追加する必要があります。

データベースにログインして以下の sql コマンドを実行してください。

mysql> ALTER TABLE <テーブル名> ADD deleted_at datetime;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0

『deleted_at』のカラムが追加されたことを確認します。

mysql> desc <テーブル名>;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255) | NO   | UNI | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
| deleted_at | datetime     | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

 

以上で Rails アプリケーションへの論理削除の導入が完了しました。

おさらいすると以下の3つの作業が必要となります。

  1. gem の導入(Gemfile へ記載してインストール)
  2. ApplicationRecord への設定追加
  3. DBに『deleted_at』と言うカラムの追加

これで destory や destroy_all メソッドを実行しても、DB のデータが論理削除されるように変わりました。

destroy_all - リファレンス - - Railsドキュメント

動作確認

本当に論理削除が出来ているかを確認します。

はじめに DB の中身を確認します。この時点では全てのデータが存在しています。

mysql> select * from users;
+----+-----------------------+---------------------+------------------+------------+
| id | name | created_at | updated_at | deleted_at |
+----+-----------------------+---------------------+------------------+------------+
| 1 | aaaaa | 2017-05-01 06:02:54 | 2017-05-01 06:02:54 | NULL |
| 2 | bbbbb | 2017-05-01 06:02:54 | 2017-05-01 06:02:54 | NULL |
| 3 | ccccc | 2017-05-01 06:02:54 | 2017-05-01 06:02:54 | NULL |
+----+-----------------------+---------------------+------------------+------------+
3 rows in set (0.00 sec)

 

コンソール経由で削除を実行します。

$ rails c
Loading development environment (Rails 5.0.2)
irb(main):001:0> User.destroy_all(id: 3) # id:3 のレコードを削除します
=> [# User id:="" 3="" name:="" created_at:="" 2017-05-01="" 06:02:54="" updated_at:="" 2017-09-16="" 06:10:23="" deleted_at:="" gt="" code="">

 

すると、id: 3 のレコードの deleted_at にタイムスタンプが記録されました。

destory_all メソッドを実行しても物理削除されていないことが分かります。

mysql> select * from users;
+----+-----------------------+---------------------+---------------------+------------+
| id | name | created_at | updated_at | deleted_at |
+----+-----------------------+---------------------+---------------------+------------+
| 1 | aaaaa | 2017-05-01 06:02:54 | 2017-05-01 06:02:54 | NULL |
| 2 | bbbbb | 2017-05-01 06:02:54 | 2017-05-01 06:02:54 | NULL |
| 3 | ccccc | 2017-05-01 06:02:54 | 2017-09-16 06:10:23 | 2017-09-16 06:10:23 |
+----+-----------------------+---------------------+---------------------+---------------------+
3 rows in set (0.00 sec)

 

find_by メソッドでデータが取得出来るか確認します。

$ rails c
Loading development environment (Rails 5.0.2)
irb(main):001:0> User.find_by(id: 3)
=> nil

irb(main):002:0> User.with_deleted.find_by(id: 3)
=> # User id: 3, name: "トレンド", created_at: "2017-05-01 06:02:54", updated_at: "2017-09-16 06:10:23", deleted_at: "2017-09-16 06:10:23">

find_by メソッドを実行しても論理削除されているデータは取得できません。

一応、論理削除されたデータも取得出来る with_deleted と言うオプションもあります。

 

ちなみに復元用のメソッドも用意されており、簡単に元に戻せます。

$ rails c
Loading development environment (Rails 5.0.2)
irb(main):001:0> User.with_deleted.find_by(id: 3).restore
=> # user id:="" 3="" name:="" created_at:="" 2017-05-01="" 06:02:54="" updated_at:="" 2017-09-16="" 09:52:34="" deleted_at:="" nil="">

まとめ

Rails アプリケーションで 論理削除を導入する方法をまとめました。

導入までのステップは 3つだけでかなり簡単でした。

運用管理上『created_at』『updated_at』『deleted_at』は必要なカラムだと思います。

これらのカラムの存在は不具合対応などを迅速に処理できるようサポートしてくれます。

まだ、導入していないアプリケーションでは是非導入を検討してみて下さい。