2013-06-13 2 views
7

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

UserMailer.password_reset(user).deliver 

Но если заглянуть внутрь UserMailer мы можем увидеть это:

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

Обратите внимание, что имя метода не с префиксом self. Глядя на это, кажется, вам нужно создать экземпляр объекта сначала, как показано ниже. Как Rails это делает?

UserMailer.new.password_reset(user).deliver 

ответ

10

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

спасибо. Но почему бы просто не сделать его классным методом? Что мы получаем от этого подхода? – dee

+0

Я не уверен, полностью ли я понимаю. Вы имеете в виду, почему бы не сделать его методом экземпляра? Итак, как UserMailer.new.password_reset (пользователь) .deliver? – Rebitzele

+0

Я имею в виду, почему использование метода отсутствует? Сохраните его 'UserMailer.password_reset (user) .deliver', но измените' def method' на 'def self.method' – dee

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