LoginSignup
23
16

More than 3 years have passed since last update.

Railsで論理削除(soft delete)を実装する(discard gem利用)

Last updated at Posted at 2019-10-21

環境

  • Rails 5.2.3
  • Ruby 2.6.5
  • Discard 1.1.0

Gemの選択に要注意

  • paranoiaは、自らのREAMDEで「新規にプロジェクトに導入するのは非推奨」としている。
  • 同READMEで推奨されているdiscardを使う。

非推奨の背景

  • ActiveRecordのdeletedestroyをoverrideしているため、開発者が予期しない挙動をする。
  • dependent: :destroy関連のレコードは削除(物理削除)される(※開発者が期待する動作ではない)。

上記に伴い、バグフィックスと、Railsの新しいバージョンへの対応は行うが、新しいfeatureは受け付けていない。

Discardの導入

Gemのインストール

Gemfile
gem "discard"
$ bundle install

db migration

posts テーブルに適応する例。

$ rails generate migration add_discarded_at_to_posts discarded_at:datetime:index

以下のようなファイルが生成される。

class AddDiscardedAtToPosts < ActiveRecord::Migration[5.2]
  def change
    add_column :posts, :discarded_at, :datetime
    add_index :posts, :discarded_at
  end
end
$ rails db:migrate

モデルに定義追加

class Post < ApplicationRecord
  include Discard::Model
end

使い方

削除

destroyの代わりに、discardを使う。

@post.discard

コマンド実行例

# 削除
post.discard       # => true
# 確認
post.discarded?    # => true

# 強制削除。既に削除済の場合は、exceptionが発生する。
post.discard!      # => true
post.discard!      # Discard::RecordNotDiscarded: Failed to discard the record

# 削除したレコードを元に戻す
post.undiscard     # => true
post.undiscard!    # => Discard::RecordNotUndiscarded: Failed to undiscard the record
post.discarded_at  # => nil

# 削除した日時を確認
post.discarded_at  # => Mon, 21 Oct 2019 14:34:41 JST +09:00

# 削除されたレコード一覧
Post.discarded     # => [#<Post:0x00007fc04dbe3010 ...]
# 削除されていないレコード一覧
Post.kept          # => []

default_scopeの導入について

デフォルトでは、Post.allは削除されたレコードも含めて返す。
この挙動を変えて削除されていないものだけ返すようにするには、default_scope -> { kept }を設定する。

class Post < ApplicationRecord
  include Discard::Model
  default_scope -> { kept }
end

Post.all                       # 削除されていないレコードのみ
Post.with_discarded            # 全てのレコード
Post.with_discarded.discarded  # 削除されたレコードのみ
23
16
0

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
23
16