6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ActionMailerのアクションメソッドは遅延評価されるので注意

Posted at

分かっている方も多いかもしれませんが、以下のコードは一見例外が起こりそうですが起きません。
以下のコードでは、HogeMailerのインスタンスメソッドdaily_summaryの中身は評価されないからです。(irb等だとinspectメソッドあたりが呼ばれるせいで評価されてしまいますが…)

class HogeMailer < ActionMailer::Base
  def daily_summary(user)
    mail(to: user.email)
  end
end

HogeMailer.daily_summary(nil)
# => #<ActionMailer::MessageDelivery>

メーラーのアクションを呼んだ場合の評価の流れ

http://railsguides.jp/action_mailer_basics.html を見ると書いてありますが、
このHogeMailerクラスのdaily_summaryメソッド(アクションと呼ばれます)を呼んだ場合はActionMailer::MessageDeliveryというMail::Messageをラップしたクラスのインスタンスが返されます。

(内部的にはActionMailer::Baseのmethod_missingメソッドが呼ばれ、ActionMailer::MessageDeliveryクラスのインスタンスが作られます。 )

ActionMailer::MessageDeliveryのコードは以下のようにDelegatorになっていて、Mail::Messageのように振る舞うのですが、インスタンスが作られた段階ではまだ@mail_methodが呼ばれていません。必要になった際に初めて呼ばれて@mail_methodのメソッドの中身が評価されます。

class MessageDelivery < Delegator
  def initialize(mailer, mail_method, *args) #:nodoc:
    @mailer = mailer
    @mail_method = mail_method
    @args = args
  end

  def __getobj__ #:nodoc:
    @obj ||= @mailer.send(:new, @mail_method, *@args).message
  end
  # ...

(https://github.com/rails/rails/blob/v4.2.6/actionmailer/lib/action_mailer/message_delivery.rb から引用)

なんでこういう仕様なのか

なぜ、こういう仕様になっているかというと、非同期送信機能(deliver_laterメソッド)との兼ね合いのためでしょう。

言われると確かにという感じですが、意識しないとテストなどで、最初のHogeMailer.daily_summary(nil)みたいな、一見テストしているけど実はしてないようなコードを書いてしまうことがあるので気を付けましょう…
テストで使う際はdeliver_nowまたはmessageを必ず呼ぶようにしましょう。どちらもMail::Messageを返します。

ちなみに

HogeMailer.daily_sumary(User.first) # => NoMethodError
HogeMailer.daily_summary() # => #<ActionMailer::MessageDelivery>

1番目のコードはActionMailer::Baseのmethod_missing内で呼ばれたメソッドがアクションとして存在するかチェックされるので例外を起こすのですが、2番目は必要になるまでアクションメソッドが評価されないので、例外が起きません。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?