问题
When sending mail in Rails, usually one would do something like this:
UserMailer.password_reset(user).deliver
But if we look inside UserMailer we can see this:
def password_reset(user) # not self.password_reset
# ...
end
Notice that the method name is not prefixed with self. Looking at it, it seems like you need to instantiate the object first as below. How does Rails do this?
UserMailer.new.password_reset(user).deliver
回答1:
That's a great question. In the source (https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb), Rails uses method_missing to create a new instance of the ActionMailer. Here's the relevant excerpt from the source:
def method_missing(method_name, *args) # :nodoc:
if respond_to?(method_name)
new(method_name, *args).message
else
super
end
end
回答2:
Please note that the self.deliver method is deprecated, have a look at the code given below. Since deliver method is defined as a class method you don't have to instantiate the mailer class.
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
Sending mail
Once a mailer action and template are defined, you can deliver your message or create it and save it for delivery later:
mail = Notifier.welcome(david) # => a Mail::Message object
mail.deliver # sends the email
#Above 2 steps can be combined
Notifier.welcome(david).deliver
You never instantiate your mailer class. Rather, you just call the method you defined on the class itself.
The method
password_resetreturns a Mail::Message object which can then just be told deliver to send itself out.
来源:https://stackoverflow.com/questions/17088619/how-can-you-call-class-methods-on-mailers-when-theyre-not-defined-as-such