2013-06-13 9 views
7

Quando si invia la posta in Rails, di solito si potrebbe fare qualcosa di simile:Come puoi chiamare i metodi di classe sui mailer quando non sono definiti come tali?

UserMailer.password_reset(user).deliver 

Ma se guardiamo dentro UserMailer Possiamo vedere questo:

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

Si noti che il nome del metodo non è preceduto da self. Guardandolo, sembra che tu abbia bisogno di istanziare l'oggetto prima come di seguito. Come fa Rails a fare questo?

UserMailer.new.password_reset(user).deliver 

risposta

10

Questa è una bella domanda. Nell'origine (https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb), Rails utilizza method_missing per creare una nuova istanza di ActionMailer. Ecco il brano in questione dalla fonte:

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

Grazie. Ma perché non renderlo un metodo di classe? Cosa otteniamo da questo approccio? – dee

+0

Non sono sicuro se capisco del tutto. Intendi perché non renderlo un metodo di istanza? Quindi, come UserMailer.new.password_reset (utente) .deliver? – Rebitzele

+0

Intendo perché manca il metodo di utilizzo? Tienilo 'UserMailer.password_reset (user) .deliver' ma cambia' def method' in 'def self.method' – dee

0

Si prega di notare che il metodo self.deliver è deprecato, uno sguardo al codice indicato di seguito. Poiché il metodo deliver è definito come metodo di classe, non è necessario creare un'istanza della classe 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 

invio di posta elettronica

volta un'azione mailer e il modello sono definiti, è possibile inviare il messaggio o di crearla e salvarla per la consegna più avanti:

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

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

Non si può mai un'istanza la classe mailer. Piuttosto, chiami semplicemente il metodo che hai definito sulla classe stessa.

Il metodo restituisce un oggetto password_reset Mail :: Messaggio che possono poi essere appena detto consegnare per inviare se stesso.