Rails 5 モデルの条件付きbefore_destroy


Published on

Rails 5 でモデルに条件付き before_destroy を設定する方法。

例えば Post モデルがあって、レコードを消す前に条件判定をするとする。ステータスがアクティブだったら消さない。アクティブ以外の場合だけレコードを消しても Ok としたい。

そこで以下のようなコードを書いても動かない。


class Post  < ApplicationRecord

  before_destroy :do_not_destroy_active_post

  private

  def do_not_destroy_active_post
    return false if active?
  end
end

どうすればいいのかはここ(Active Record Callbacks)に書いてある。

If the before_validation callback throws :abort, the process will be aborted and ActiveRecord::Base#save will return false. If ActiveRecord::Base#save! is called it will raise an ActiveRecord::RecordInvalid exception. Nothing will be appended to the errors object.

動くコードはこんな感じになる。


class Post  < ApplicationRecord

  before_destroy :do_not_destroy_active_post

  private

  def do_not_destroy_active_post
    throw(:abort) if active?
  end
end

エラーメッセージを加えたければ、throw(:abort)をする前に errors.add すればできる。

ほとんどお約束みたいなことで、現行のプロジェクトを検索してみたらたくさん throw(:abort)が引っかかるが、全てこの条件付き before_destroy だった。私自身の経験としてもこれ以外で throw(:abort)を使ったことが無いのだが。。。

結論としては throw(:abort)したら Ok ってことなんだけど、他の技術ブログで Rails 4からの歴史的経緯とか長々と書いてあって「ググってこういう記事に辿り着いた人ってそんなゴチャゴチャと昔話しまで求めてないのでは」と思ったので簡素に結論だけ書いて終わりにしたい。

関連記事