问题
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_reset
returns 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