何を書いているか?
DBの保存前と保存後の判定の仕方に1日詰まってしまい、せっかくなので備忘録として書いてます。
どういう状況で詰まったか
after_commitスコープ内で、DBの保存前と保存後で比較し、保存・更新・削除されていれば、trueを返す処理をしたかったのですが、この「after_commit後の判定」というところでひっかかりました。しかも子モデルのテーブルだったのでなおさら…💧
親モデルと子モデルの関係
# User.rb(親モデル)
class User < ApplicationRecord
has_many :posts
end
# Post.rb(子モデル)
class Post < ApplicationRecord
belongs_to :user
end
DBにガッツリ保存された後に判定する
もうどうしようもないと挫けそうでしたが(笑)なんとか方法があったので書きます。
保存する前であれば、さまざまメソッドはあります。
attr_was(現在は非推奨のようですが…)したり、changesやprevious_changes、attr_previously_changedなどなど。
しかし、after_commitスコープ内ではこれらは通用しません。
何せ、もうDBに入ってしまっているのですから…
しかし、このafter_commit内で,「DB保存前とDB保存後のレコードの数を比較して条件分岐」
という状況が訪れました。
データの変更(update)・追加(create)については
# User.rb(親モデル)
def posts_changes?
posts.any? {|c| c.content_previously_changed? }
end
# postsテーブルにはcontentというカラムがある前提です
のようなメソッドをUser.rb(親モデル)に定義することでクリアすることができました。
それがこちらです。
# User.rb(親モデル)
around_save :around_save_posts_comparison
def around_save_posts_comparison
@posts_before_save_count = posts.count
yield
@posts_after_save_count = posts.count
end
around_save
これは、「saveの途中の処理」ということらしく、yield前にsave前、後にsave後のものが入ります。
これを使い、インスタンスメソッドを定義しました。
それを使い、
# User.rb(親モデル)
after_commit do
if @posts_before_save_count != @posts_after_save_count
puts "レコードの数が変わったよ!新しく追加されたか削除されているよ!"
end
end
このようして、なんとか処理を書くことができました。。
さっきのprevious_changed?とまとめると…
def posts_changes?
posts.any? {|c| c.content_previously_changed? } ||
(@posts_before_save_count != @posts_after_save_count)
end
after_commit do
if posts_changes?
puts "レコードの数が変わったか、新しく追加されたか削除されているか、変更されているよ!"
end
end
ただ、先輩からは「ちょっと見た目やばい。…ただ、他に処理が思いつかないから一旦これでいいか」
という感じなので、他に答え知っている方は教えていただけるとありがたいです。。
参考記事