Ruby
Rails
ActionMailer
メタプログラミング
委譲

Rubyはメタプログラミングに秀でた言語ですが、メタプログラミングを多用したRailsなどでは、思わぬ挙動にハマることがあります。

REPLコンソール

irbpry、Railsの画面内に表示させるweb-consoleなど各種ありますが、入力したものをその場で実行するREPLコンソールは便利なものです…が、これが罠になった例がありました。

REPLコンソールでは、入力して実行したコードの結果を表示するのですが、表示のために#to_s、あるいは#inspectと言ったメソッドを実行します。通常であれば特に問題ない操作なのですが、ときにはそれでオブジェクトが状態を変えてしまうことがありえます。

メーラーと中身

Rails標準で搭載されているActionMailerですが、これもまた黒魔術を多用した構成となっています。そして、メーラーを作成してREPLで評価すると、以下のようになります。

> SomeMailer.some_method(args)
=> #<Mail::Message ....>  

実はこの時点で、もう罠にハマっています。

実際の動作

メーラーで作成したもののクラスはActionMailer::MessageDeliveryというものです。このクラスは、delivery_nowなど配信制御系のメソッドを除けば、内部で持つMail::MessageへのDelegatorとなっているので、#inspectを実行すればその瞬間にメール生成処理が走って、そのインスタンスの詳細を返しています。

さらに、このメールを.deliver_laterしようとした場合、事前にMail::Messageを生成してしまっているとエラーになります

結論

REPLで「結果を表示する」こと自体も1つの処理で、時にはそれが原因でオブジェクトそのものが挙動を変化させてしまうことすら、ありえます。挙動がドキュメントやコードで確認できるものについては、結果を鵜呑みにせず、資料を丁寧に追っていくほうが正解かもしれません。