2013-06-13 12 views
7

Wenn E-Mails in Rails zu senden, in der Regel würde man so etwas tun:Wie können Sie Klassenmethoden für Mailer aufrufen, wenn sie nicht als solche definiert sind?

UserMailer.password_reset(user).deliver 

Aber wenn wir in UserMailer aussehen können wir sehen:

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

Beachten Sie, dass der Methodenname mit nicht voran self. Wenn Sie es betrachten, scheint es, als ob Sie das Objekt zuerst wie unten beschrieben instanziieren müssen. Wie macht Rails das?

UserMailer.new.password_reset(user).deliver 

Antwort

10

Das ist eine gute Frage. In der Quelle (https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb) verwendet Rails method_missing, um eine neue Instanz des ActionMailer zu erstellen. Hier ist der relevante Auszug aus der Quelle:

def method_missing(method_name, *args) # :nodoc: 
    if respond_to?(method_name) 
    new(method_name, *args).message 
    else 
    super 
    end 
end 
+0

Vielen Dank. Aber warum nicht einfach eine Klassenmethode? Was gewinnen wir von diesem Ansatz? – dee

+0

Ich bin mir nicht sicher, ob ich alles verstehe. Meinst du, warum es nicht zu einer Instanzmethode machen? Also, wie UserMailer.new.password_reset (user) .deliver? – Rebitzele

+0

Ich meine, warum verwenden Methode fehlt? Behalte es 'UserMailer.password_reset (user) .deliver', aber ändere' def method' in 'def self.method' – dee

0

Bitte beachten Sie, dass die self.deliver Methode veraltet ist, haben einen Blick auf den Code unten. Da die Methode deliver als Klassenmethode definiert ist, müssen Sie die Mailerklasse nicht instanziieren.

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 

Senden Mail

Sobald ein Mailer Aktion und Vorlage definiert sind, können Sie Ihre Nachricht liefern oder sie erstellen und für die Lieferung sparen später:

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

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

Sie instanziieren nie Ihre Mailerklasse. Stattdessen rufen Sie einfach die von Ihnen definierte Methode für die Klasse selbst auf.

Verfahren password_reset eine Mail :: Message-Objekt zurückgibt, die dann liefern kann nur gesagt, selbst auszusenden.