gahyuuuuuuuu
@gahyuuuuuuuu (hyuga yuki)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

validates on: :destroy

Discussion

解決したいこと

user.destroy 実行時に、ユーザーが管理者権限になっている場合は削除できないという要件(バリデーション)を実装したいと考えています。
before_destroyfalse を返す以外に良い方法はありますか?

発生している問題・エラー

以下の様に書きたいのですが、on: :destroy などの記述はできない(用意されていない)と思います。

models/user.rb
enum account_type: {
  viewer: 'viewer',
  administrator: 'administrator'
}

with_options on: :destroy do
  validates :account_type, exclusion: { in: %w(administrator) }
end

before_destroy コールバックで false を返すと実現できる様なのですが、以下の理由で他の方法を探しています。

  • コールバックにロジックが記述されているのは良くないという記事を見たことがあります。
  • バリデーションっぽいのでコールバックとして書きたくない

他にいい方法はありますでしょうか。

あるいは、オプションが無いということは削除を弾くという考え方(設計?)がよろしくないかもね、という事なのでしょうか? 
(権限があってできることが異なる場合、それは同じモデルとして扱うのは良くないよね、など)

0

validate は,保存されたデータが適切な状態かどうかセーブ前に行うチェック機構と考えています.

ですので,on: :destroy だとあまり私自身のイメージとはマッチしないです.
(削除されてしまうので,残った状態が valid かどうかとは別もの?

before_destroy や,その他の事前チェックで実装できるならそちらを選択する気はします.

Refs

1Like

案1 : on: :destroy_setupで定義して、userモデルに以下のようなメソッドを用意すれば解決はできますね。

def destroy_with_validation
  return unless self.valid?(:destroy_setup)
  self.destroy
end

案2 : 論理削除にしてupdateで対処する

2案書きましたが正直before_destroyでやってしまうのが良いかなって思っています。
下記の通り例を見るとbeforeの処理でvalidationを書くことはある程度想定されてそうです。
https://speakerdeck.com/claudiob/better-callbacks-in-rails-5?slide=9

before_destroyを使いたくない理由として

コールバックにロジックが記述されているのは良くないという記事を見たことがあります

としていますが、根本にあるのは、処理を実行したときに何が起こるかわかりにくいということです。
例えばvalidation_destroyed_user_authorityとかvalidationであることがわかるメソッドで定義して、before_destroyではそれを呼び出すようにしておけば、良いのではないでしょうか。

1Like

Your answer might help someone💌