あるモデルがあって、#save が実行されたときに同一モデル内で複製したインスタンスも一緒に保存したかった。一個目の #save が走る前にコールバックメソッドを使って複製したインスタンスを保存するようにした。コードだと以下のような感じ。
class Model
before_validation :method_one
before_create :method_two
def method_one
...
end
def mothod_two
Model.reset_callbacks(:validation)
Model.reset_callbacks(:create)
@model = Model.new
@model.save
end
end
なんで reset_callbacks 呼んでるのかというと二回コールバックメソッドを走らせないため。一回目の #save (コントローラーから呼ばれる)が呼ばれたときだけコールバックメソッドを実行して、二回目の #save (モデルのコールバックメソッド内で呼ばれる)では実行したくないから。
しかしここではまってしまった。なんとコールバックメソッドで複製したドキュメントを DB 内で確認すると created_at が空になっている。なんじゃこりゃ。
どうも reset_callbacks(:create)
がいかんかったみたい。ORM が実行する create 周辺のコールバックメソッドも軒並みリセットされてしまう模様。
そういうわけで以下の様にして解決した。
class Model
before_validation :method_one
before_create :method_two
def method_one
...
end
def hoge
Model.skip_callback :create, :before, :sell
Model.skip_callback :create, :after, :send_notification
Model.reset_callbacks(:validation)
@model = Model.new
@model.save
end
end
callback、便利だけど奥が深い。ちなみにこれら skipp_callback とか reset_callbacks とかは ActiveModel や ActiveRecord (僕はMongoidで開発してます)などの OR マッパーのメソッドではなく、 ActiveSupport::Callbacks のメソッドだったりします。ActiveSupport も奥が深い。