個人開発で使うGemにseedfuを使おうとしたのですが、5年前から更新がされておらず自分がプロダクトで使っているRails7にはもちろん対応していなかったので、forkして更新することにしました。その際にハマったことについて、今度同じことではまらないように備忘録として残しておきたいと思います。
コールバックで戻り値をfalseにしたときの挙動が変更
seedfu
のGemの中ではbefore_save { false if fail_to_save }
が書かれていました。Railsガイドによると、Rails4ではコールバックのブロックの中でfalse
を返すと、すべてのコールバックチェインが停止する仕様とありました。
つまり、ロールバックされ、record.save
はfalseになります。実際に戻り値はfalseになっていました。(ロールバックされるかについて実際に試したわけではないので間違っていたらすいません♂️)
しかしRails5以降では、コールバックチェーンは停止しないようになっていて、停止するには、throw(:abort)
で明示的に書く必要があるようです。
下のように書くことで、意図した挙動になりました。マージはされてませんが(というよりメンテナンスされてない。。)、こちらでパッチが当てられていました。
if ActiveRecord::VERSION::MAJOR < 5
before_save { false if fail_to_save }
else
before_save { throw :abort if fail_to_save }
end
Rails5.0ではコールバックの中でfalse
を返していると以下のようにWarningが出るようになってました。
WARNING: Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1. To explicitly halt the callback chain, please use `throw :abort` instead.
さいごに
このBreaking Changeは知らなかったので、何でだということでハマってしまいました。
ここまで読んでいただきありがとうございました。
Twitterもやってますので、フォローしていただけるとうれしいです。