为什么Rails实例方法可以在rspec中用作类方法

时间:2015-05-27 05:12:20

标签: ruby-on-rails ruby ruby-on-rails-3 rspec actionmailer

我在一篇关于在Rails应用程序中发送邮件的文章中找到了一个片段:

class ExampleMailerPreview < ActionMailer::Preview
  def sample_mail_preview
    ExampleMailer.sample_email(User.first)
  end
end

在此链接中:http://www.gotealeaf.com/blog/handling-emails-in-rails

我不知道为什么方法:sample_email(),在我看来应该是一个实例方法,可以像ExampleMailer.sample_email()一样在类方法中访问。谁能解释一下?

1 个答案:

答案 0 :(得分:3)

它不是一个特定的东西,它是一个ActionMailer的东西。看着:

https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb

看一下第135-146行的评论:

# = Sending mail
#
# Once a mailer action and template are defined, you can deliver your message or defer its creation and
# delivery for later:
#
#   NotifierMailer.welcome(User.first).deliver_now # sends the email
#   mail = NotifierMailer.welcome(User.first)      # => an ActionMailer::MessageDelivery object
#   mail.deliver_now                               # generates and sends the email now
#
# The <tt>ActionMailer::MessageDelivery</tt> class is a wrapper around a delegate that will call
# your method to generate the mail. If you want direct access to delegator, or <tt>Mail::Message</tt>,
# you can call the <tt>message</tt> method on the <tt>ActionMailer::MessageDelivery</tt> object.

通过在ActionMailer :: Base类上定义一个类似于:

的method_missing方法来实现该功能。
  def method_missing(method_name, *args) # :nodoc:
    if action_methods.include?(method_name.to_s)
      MessageDelivery.new(self, method_name, *args)
    else
      super
    end
  end

基本上,在ActionMailer实例上定义一个方法(在注释示例中为NotifierMailer),然后在类上调用它,会创建一个新的MessageDelivery实例,该实例将委托给ActionMailer类的新实例。