Edited at

Railsのcallbackについて調べた

More than 1 year has passed since last update.

色々詰まったので勉強がてらまとめてみた

Railsのバージョンは3.2


callbackとは


  • オブジェクトの生成・更新・削除のタイミングで呼び出されるメソッド

  • トリガとなるイベント(create, saveなど)の前後に登録可能

  • トリガに対してメソッドを共通化できて便利


callbackの順番

create,update,find,destroyでまとめた

それぞれ上から順番に実行される


create


create_test.rb

hoge = Hoge.new(name: "hoge")

#initialize
after_initialize #newメソッドで生成したときのみ
hoge.save!
#BEGIN TRANSACTION
before_validation
#validation
after_validation
#ROLLBACK
after_rollback #validationに失敗した時のみ
before_save
around_save
before_create
around_create
#INSERT INTO "hoges"
after_create
after_save
# COMMIT
after_commit


update


update_test.rb

hoge.update(name: "fuga")

#BEGIN TRANSACTION
before_validation
#validation
after_validation
#ROLLBACK
after_rollback #validationに失敗した時のみ
before_save
around_save
before_update
around_update
#UPDATE "hoges" SET
after_update
after_save
# COMMIT
after_commit


find


find_test.rb

hoge = Hoge.first

# SELECT hoges.* FROM
#initialize
after_initialize
after_find


destroy


destroy_test.rb

hoge.destroy

#BEGIN TRANSACTION
before_destroy
around_destroy
#DELETE from hoges
after_destroy
# COMMIT
after_commit


changed?が使用できるcallback

要素の変更を確認できるchanged?メソッドが使えるcallbackを調べた。


changed_method.rb

# ここから→

before_validation
after_validation
after_rollback
before_save
around_save
before_update
around_update
after_update
after_save
# →ここまでは使える
after_commit #使えない


changed?系のメソッド一覧


change_series.rb

hoge = Hoge.find_by(name: hoge)

hoge.name = fuga

#objectが変更されたか?
hoge.changed? #=>true
#指定要素が変更されたか?
hoge.name_changed? #=>true
#指定要素がhogeからfugaに変更されたか?
hoge.name_changed?(from: hoge, to:fuga) #=>true
#指定要素の変更前の値?
hoge.name_was #=>”hoge”
#指定要素の変更前後の値
hoge.name_change #=>[“hoge”, “fuga”]
#変更要素名
hoge.changed #=>[“name”]



accepts_nested_attributes_forを使った時のcallbackの順番

上から順番に処理されます。

ややこしいのであんまり使いたくない。

親:before_validation

子:before_validation

子:after_validation

親:after_validation

親:before_save

親:around_save

親:before_xxx

親:around_xxx

子:before_save

子:around_save

子:before_xxx

子:around_xxx

子:after_xxx

子:after_save

親:after_xxx

親:after_save


around_xxxの使いドコロ

around_xxxの使いドコロがよく分からなかったので調べてみた。

トリガーの前後で処理を定義できるっぽい。便利そう。


around_xxx.rb

def around_save

# 何かしらの処理
yield #saves
# 何かしらの処理2
end