Ruby
Rails
callback

Railsのcallbackについて調べた

色々詰まったので勉強がてらまとめてみた
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