DelayedJob
時間のかかる処理や、絶対コケるとマズい部分での本質的ではない処理を、バックグラウンドでやってもらうためのgemの一つ。
Draper
表示系に責任がある処理を行う、MVCに続く第4のレイヤー、Presenterを提供する、Decoratorと呼ばれるgemの一つ。導入するとviewがすごく綺麗になって感動する。
他のDecoratorとしてはActiveDecoratorとか。
本題
「表示系だしサービス全体でDecorateしちゃって問題ないでしょ」とapplication_controller
で @product.decorate
みたいなことをしたら、DelayedJobを使用している箇所でエラーを吐いた。
RuntimeError: Found DelayedJob Error: ProductDecorator#user delegated to object.user, but object is nil: #<ProductDecorator:0x00 ... >
原因と対策
DelayedJobで何が起こってるのか
そもそもDelayedJobで何が起こっているのかを調べようとgemの中身を覗いてみたけど、今の力量じゃめっちゃ時間かかりそうなので後に回す。
今回はDelayedJob に ActiveRecord インスタンスを渡す時の注意という記事にお世話になりました。
記事によると
delay は巧妙な構文で仕組みを隠蔽しているが、実際に内部で起きていることは (中略) yaml 文字列を作って Delayed::Job のインスタンスを生成しているだけだ。
とのこと。
実際に自分で眺めてみても
def delay(options = {})
DelayProxy.new(PerformableMethod, self, options)
end
との記述が見つかる。これがyamlになるっぽくて、その過程は参考元の記事に書いてあります。
要するにyaml文字列でDelayed::Jobのインスタンスを作ろうとした際に、加工されたオブジェクトを渡そうとすると割とハマっちゃうんじゃないだろうか。
対策
DelayedJobには、ActiveRecordインスタンスを生で渡すようにすればとりあえずは大丈夫そう。
余談
ちょっとずつでいいのでgemくらい読めるくらいのエンジニアになりたいので、時間を見つけてDelayedJobとDraperの中身を漁ろうな。