論理削除とは
データを消すが情報としては残しておくみたいな使い方です。
対義語的な感じで物理削除があり
物理削除は完全にデータを消します。
Railsで言う論理削除は
データベースのレコードとしては残っているが
データを取得する時とかに論理削除されたデータは取得できないとかがあります。
paranoiaとは
論理削除を間単に実装できるGemです
Railsに実装する
Gemfileにパラノイアを追記
bundle install
gem 'paranoia'
migration
論理削除を実装したいテーブルにdeleted_at
を追加
def change
add_column :entry_lists, :deleted_at, :datetime, default: nil
add_index :entry_lists, :deleted_at
end
該当モデル
acts_as_paranoid
を追加
class EntryList < ApplicationRecord
acts_as_paranoid
これだけで論理削除が実装されます。
実際の動き
削除
任意のレコードを削除
デリート実行しているが
実際sqlはdeleted_atのupdateが行わている
entrylist.delete
EntryList Update (7.2ms) UPDATE `entry_lists` SET `entry_lists`.`deleted_at` = '2023-02-22 02:34:11', `entry_lists`.`updated_at` = '2023-02-22 02:34:11.956798' WHERE `entry_lists`.`id` = 2
=> #<EntryList:0x0000000007e7e800
id: 2,
created_at: Mon, 31 Oct 2022 17:06:07 JST +09:00,
updated_at: Wed, 22 Feb 2023 11:34:11 JST +09:00,
deleted_at: Wed, 22 Feb 2023 11:34:11 JST +09:00> ⇦削除実行した時間がはいる
取得
論理削除されたレコードを取得しようとすると存在しないエラーが返る
論理削除されたものはデフォルト含めずに取得されるので特に意識しなくてもいい感じに取得してくます
EntryList.find(2)
ActiveRecord::RecordNotFound: Couldn't find EntryList with 'id'=2 [WHERE `entry_lists`.`deleted_at` IS NULL]
取得したい場合は
with_deleted
をあいだに挟んであげると
取得できるようになる
文字通り論理削除されたものも含めて返してくれるようになる
EntryList.with_deleted.find(2)
=> #<EntryList:0x0000000008299598
id: 2,
created_at: Mon, 31 Oct 2022 17:06:07 JST +09:00,
updated_at: Wed, 22 Feb 2023 11:34:11 JST +09:00,
deleted_at: Wed, 22 Feb 2023 11:34:11 JST +09:00>
論理削除されているか確認したい
entrylist.paranoia_destroyed?
=> true
論理削除を復活
restore
で復活することができます。
ただバリデーションチェックはすり抜けるっぽいので
entrylist.valid?
とかで確認して restoreがいいと思います
entrylist.restore
(0.6ms) BEGIN
EntryList Update (0.7ms) UPDATE `entry_lists` SET `entry_lists`.`deleted_at` = NULL, `entry_lists`.`updated_at` = '2023-02-22 02:43:31.555370' WHERE `entry_lists`.`id` = 2
(8.8ms) COMMIT
=> #<EntryList:0x0000000007e7e800
id: 2,
created_at: Mon, 31 Oct 2022 17:06:07 JST +09:00,
updated_at: Wed, 22 Feb 2023 11:43:31 JST +09:00,
deleted_at: nil> ⇦ deleted_atがなくなる
配列でID渡して一括復活も可能です
EntryList.restore([id, id, ・・・id])
やっぱ物理削除したい
論理削除実装してるがこれだけは物理削除したい時
really_destroy!
entrylist.really_destroy!
EntryList Destroy (0.8ms) DELETE FROM `entry_lists` WHERE `entry_lists`.`id` = 2
(4.1ms) COMMIT
EntryList.with_deleted.find(2)
ActiveRecord::RecordNotFound: Couldn't find EntryList with 'id'=2 ⇦完全に削除されているので見つからない
削除したもののみ取得したい
only_deleted
EntryList.only_deleted
=> [#<EntryList:0x0000000008a0b4e8
id: 5,
created_at: Mon, 31 Oct 2022 17:06:16 JST +09:00,
updated_at: Wed, 22 Feb 2023 11:49:22 JST +09:00,
deleted_at: Wed, 22 Feb 2023 11:49:22 JST +09:00>,
#<EntryList:0x0000000008a0b420
id: 15,
created_at: Fri, 17 Feb 2023 14:00:57 JST +09:00,
updated_at: Wed, 22 Feb 2023 11:49:56 JST +09:00,
deleted_at: Wed, 22 Feb 2023 11:49:56 JST +09:00>]
まとめ
簡単に論理削除が実装できるので
論理削除したいときにはこれ