10

在 Rails 中发送邮件时,通常会这样做:

UserMailer.password_reset(user).deliver

但如果我们往里面看,UserMailer我们可以看到:

def password_reset(user) # not self.password_reset
  # ...
end

请注意,方法名称没有以 . 为前缀self。看着它,您似乎需要先实例化对象,如下所示。Rails 是如何做到这一点的?

UserMailer.new.password_reset(user).deliver
4

2 回答 2

12

这是一个很好的问题。在源代码 ( https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb ) 中,Rails 使用 method_missing 创建 ActionMailer 的新实例。以下是来源的相关摘录:

def method_missing(method_name, *args) # :nodoc:
  if respond_to?(method_name)
    new(method_name, *args).message
  else
    super
  end
end
于 2013-06-13T14:46:44.467 回答
0

请注意,该self.deliver方法已被弃用,请查看下面给出的代码。由于deliver方法被定义为类方法,因此您不必实例化邮件程序类。

action_mailer/deprecated_api.rb

module ActionMailer
  module DeprecatedApi #:nodoc:
  extend ActiveSupport::Concern

  module ClassMethods
  # Deliver the given mail object directly. This can be used to deliver
  # a preconstructed mail object, like:
  #
  #   email = MyMailer.create_some_mail(parameters)
  #   email.set_some_obscure_header "frobnicate"
  #   MyMailer.deliver(email)
  def deliver(mail, show_warning=true)
    if show_warning
      ActiveSupport::Deprecation.warn "#{self}.deliver is deprecated, call " <<
        "deliver in the mailer instance instead", caller[0,2]
    end

    raise "no mail object available for delivery!" unless mail
    wrap_delivery_behavior(mail)
    mail.deliver
    mail
  end

发送邮件

一旦定义了邮件操作和模板,您就可以传递您的消息或创建它并保存它以供以后传递:

mail = Notifier.welcome(david)  # => a Mail::Message object
mail.deliver  # sends the email

#Above 2 steps can be combined
Notifier.welcome(david).deliver

您永远不会实例化您的邮件程序类。相反,您只需调用您在类本身上定义的方法。

该方法password_reset返回一个 Mail::Message 对象,然后可以告诉传递它自己发送出去。

于 2013-06-13T16:32:08.217 回答