validates on: :destroy
解決したいこと
user.destroy
実行時に、ユーザーが管理者権限になっている場合は削除できないという要件(バリデーション)を実装したいと考えています。
before_destroy
で false
を返す以外に良い方法はありますか?
発生している問題・エラー
以下の様に書きたいのですが、on: :destroy
などの記述はできない(用意されていない)と思います。
enum account_type: {
viewer: 'viewer',
administrator: 'administrator'
}
with_options on: :destroy do
validates :account_type, exclusion: { in: %w(administrator) }
end
before_destroy
コールバックで false
を返すと実現できる様なのですが、以下の理由で他の方法を探しています。
- コールバックにロジックが記述されているのは良くないという記事を見たことがあります。
- バリデーションっぽいのでコールバックとして書きたくない
他にいい方法はありますでしょうか。
あるいは、オプションが無いということは削除を弾くという考え方(設計?)がよろしくないかもね、という事なのでしょうか?
(権限があってできることが異なる場合、それは同じモデルとして扱うのは良くないよね、など)
案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
ではそれを呼び出すようにしておけば、良いのではないでしょうか。