Discardを使用して論理削除する時に、バリデーションをかけて条件を満たす場合は論理削除しないようにしたいことがあるかと思います。
でも、「rails discard バリデーション」とかで調べても直接的な回答が得られませんでした。
色々調べて時間がかかったので、後学のためメモしておきます。
前提条件
Gemfile.lockより抜粋
discard (1.2.1)
activerecord (>= 4.2, < 8)
rails (7.0.3.1)
ダメなパターン
モデルファイルに下記のように記載しても、バリデーションは作動しません・・・
ダメな例1:
validate :do_not_discard_with_templates
ダメな例2:
validate :do_not_discard_with_templates, on: :discard
色々調べているうちに、「削除する場合の条件はバリデーションとは呼ばない」ことが判明・・・通常、普通に物理削除(destroy)する場合は、before_destroyを使用するようです。つまり、discardもdestroyと同じように記述すれば・・・
結論:destroy同様、before_discardで解決
結論、discardもdestroyと同じようにbefore_discardでメソッド定義すればいけます!
モデルファイル記述例:throw: abortしないと、エラーでも削除が実行されてしまいます。
class User < ApplicationRecord
include Discard::Model
before_discard :dont_discard_new_user
private
# 7日以内に作成された新規ユーザーは削除できない
def dont_discard_new_user
return if user.created_at < Time.current - 7.days
errors.add :discarded_at, '作成後7日間は削除できません。'
throw :abort
end
end
コントローラーファイル記述例:
def destroy
@user = User.find(params[:id])
flash.now[:alert] = "削除できませんでした。" unless @user.discard
render @user
end
論理削除とは言ってもdiscarded_atに時刻を入れているだけなんだから実質updateなのではと思いこんでいたのですが、裏できちんとdestroy扱いになっているようです。なので「バリデーションしたい」というのがそもそもおかしな話だったんですね。
参考
参考:https://blog.solunita.net/posts/validation-for-recoed-destroying-in-rails/
はるすと
最後まで読んでくださってありがとうございました!
コメント