7
4

More than 1 year has passed since last update.

Rails論理削除paranoia

Posted at

論理削除とは

データを消すが情報としては残しておくみたいな使い方です。

対義語的な感じで物理削除があり
物理削除は完全にデータを消します。

Railsで言う論理削除は
データベースのレコードとしては残っているが
データを取得する時とかに論理削除されたデータは取得できないとかがあります。

paranoiaとは

論理削除を間単に実装できるGemです

paranoia github

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>]

まとめ

簡単に論理削除が実装できるので
論理削除したいときにはこれ

7
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4