ベルリンのITスタートアップで働くジャバ・ザ・ハットリの日記

日本→シンガポール→ベルリンへと流れ着いたソフトウェアエンジニアのブログ

Rails 5 モデルの条件付きbefore_destroy

移転しました。

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ってことなんだけど、他の技術ブログでRails4からの歴史的経緯とか長々と書いてあって「ググってこういう記事に辿り着いた人ってそんなゴチャゴチャと昔話しまで求めてないのでは」と思ったので簡素に結論だけ書いて終わりにしたい。

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com

tango-ruby.hatenablog.com