Как можно вызывать методы класса в почтовых программах, если они не определены как таковые?


При отправке почты в Rails обычно делается что-то вроде этого:

UserMailer.password_reset(user).deliver
Но если мы заглянем внутрь UserMailer , то увидим следующее:
def password_reset(user) # not self.password_reset
  # ...
end
Обратите внимание, что имя метода не имеет префикса self. Глядя на него, кажется, что вам нужно сначала создать экземпляр объекта, как показано ниже. Как Rails это делает?
UserMailer.new.password_reset(user).deliver
2 8

2 ответа:

Это отличный вопрос. В источнике (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

Обратите внимание, что метод self.deliver является устаревшим, посмотрите на приведенный ниже код. Поскольку метод deliver определен как метод класса, вам не нужно создавать экземпляр класса mailer.

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, который затем можно просто сказать deliver , чтобы отправить себя.