環境
- Rails 5.2.3
- Ruby 2.6.5
- Discard 1.1.0
Gemの選択に要注意
非推奨の背景
- ActiveRecordの
delete
やdestroy
を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 # 削除されたレコードのみ