Discardによる論理削除時にバリデーションをかける(Rails7)

Rails・Webシステム開発
Anja🤗#helpinghands #solidarity#stays healthy🙏によるPixabayからの画像
スポンサーリンク

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/

はるすと
はるすと

最後まで読んでくださってありがとうございました!

この記事を書いた人
こもれびエンジニア

自然と自由を愛するエンジニア。2021年1月に、大手製造業設計からプログラマ(Rails, AWS)へ転職。動物や自然との触れ合いや、汗を流すのが好き。

/HSP(繊細さん)/18デリケートな象/ストレングスファインダー(1分析思考/2親密性/3学習欲/4調和性/5収集心)、テニス、合気道、登山、あいだみつを、ジブリ、ワンピース、ドラゴンボール、AWS、Ruby on Rails、アイミング

twitterをフォローして、記事にならないちょっとした豆知識もチェック!
Rails・Webシステム開発
スポンサーリンク
SNSでシェア/コメントして、自分のアウトプット/発信力を高めるのにお使いください。 ↓ 各ページへジャンプ ↓
twitterをフォローして、記事にならないちょっとした豆知識もチェック!
スポンサーリンク
「そんなか」サイト

コメント

タイトルとURLをコピーしました