LoginSignup
4
1

More than 3 years have passed since last update.

【Rails】on: :actionの条件付きで設定したコールバックはskip_callback、set_callbackを用いて回避することができない

Last updated at Posted at 2020-09-24

skip_callbackとset_callbackを用いて一時的にコールバックを回避しようとしたらset_callbackがうまくいかなかった。その時の状況と回避策を記録。

やりたいこと

こちらのコールバックを一時的にスキップしたい。
ruby
before_validation :func, on: :action

最初にやったこと

skip_callbackset_callbackを用いて実装した。

skip_callback(:validation, :before, :func)
------------------------------------------
# 処理を実行
------------------------------------------
set_callback(:validation, :before, :func)

しかし、このあと他の動作に不具合が出てしまい、原因を調査した。

skip_callback、set_callbackとは

skip_callbackは設定されているコールバックをスキップさせることができる。ただし、一度実行するとずっとskipしたままになってしまうため、set_callbackを用いて戻す必要がある。

うまくいかない原因

on: :actionの再設定ができていないため。

つまり、以下のようにコールバックの設定が変わってしまっていたため、挙動が変わってしまった。

# スキップ前
before_validation :func, on: :action
# スキップ後
before_validation :func

対処

最初に行ったset_callbackは、on: :actionに関して特に指定をしていない。
ruby
set_callback(:validation, :before, :func)

set_callbackでは、on: actionの設定をしておらず、on: actionの設定が無くなってしまっていた。

on: :actionの設定をしなければいけないため、onで設定している場合はその設定も引数に入れなければならないらしい。

set_callback(:validation, :before, :func, on: :action)

しかし、こちらをやってみても改善されず。

ソースを調べてみた。
https://github.com/rails/rails/blob/070d4afacd3e9721b7e3a4634e4d026b5fa2c32c/activesupport/lib/active_support/callbacks.rb#L674

ソースコードにコメントしてある引数にはif, unless, prependしか無いためon: :actionの設定は難しそう。

最終的な対処法としては、コールバックを回避して処理を行うメソッドが存在するため、こちらを用いることにした。
https://railsguides.jp/active_record_callbacks.html#%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%90%E3%83%83%E3%82%AF%E3%82%92%E3%82%B9%E3%82%AD%E3%83%83%E3%83%97%E3%81%99%E3%82%8B

まとめ

skip_callbackset_callbackはコールバックを回避するための便利なメソッドですが、onを用いた条件付けがされている場合かつ全てのコールバックを回避しても問題ない場合はそもそもコールバックを回避できるメソッドを使った方が良いのかなと今のところ考えています。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1