ActiveRecordのinitialize飛ばし


ActiveRecordを使っていたところ、意外な挙動をすることがありましたが、実はRubyの標準機能で実現できることでした。

initialize…されない!?

ActiveRecordにある処理を組む過程で、(素直にafter_initializeを使えばいいものを)何を思ったかinitializeのオーバーライドを行って実装する…というように書いてしまったのですが、そのinitialize内の処理が、ときどきしか実行されないということに気づきました。

調べてみると、ActiveRecordを本当にnewする際にはinitializeが呼ばれるのですが、ActiveRecord::Relationから実体化するなど、DBから引いてきたときにはinitialize走らないとのことでした。

Ruby標準で作れる、未初期化オブジェクト

では、一体どんな手法を使えばinitializeしないオブジェクトを作れるのだろうと調べてみたら、じつは標準ライブラリにClass#allocateというのがあって、これを使うとまさに「特定のクラスだけど、inializeしていないオブジェクト」を作れるということでした。

ActiveRecordの場合は、「どうせすぐにデータを詰めるのだから、initializeは無駄」という最適化なのでしょうが、なかなか使う機会の少ない機能かなという気もしています。

余談

initializeをオーバーライドする際に、引数は直接superに投げるだけで、オーバーライドした中では使わない、というような状況の場合、変数名を省略することもできます。

def initialize(*)
  #元の引数、ブロックはそのままsuperへ
  super

  #引数を使わない拡張処理
end