Ruby class vs 实例方法混淆

Ruby class vs instance method confusion

给定 class:

class UserMailer < ActionMailer::Base
  default from: "do-not-reply@mark.com"
  def contact_email(contact)
    @contact = contact
    mail(to: 'm@mark.com', from: @contact.email, subject: "Website Contact")
  end
end

和以下测试代码:

c = Contact.new
UserMailer.contact_email(c)

这段代码如何工作?我认为我的 contact_email 是一个实例方法,但它被作为 class 方法调用,并且它有效。

感谢您的帮助 - 在我学习 Ruby 和 Rails :)

-标记

乍一看这看起来不对,你完全正确。

之所以有效,是因为有一个 method_missing class (see source) 看起来像这样

  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

action_methods 基本上是与可以发送的电子邮件相对应的邮件程序方法的名称,MessageDelivery 是一个小代理 class 最终会做

YourMailer.new.send(:contact_mailer, ...)

我不明白为什么要这样做,但是实例方法代理的基本 class 方法从很早以前就以一种或另一种形式存在动作邮件

勾选source

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

实施示例:

class MyMailer
  def self.method_missing(method, *args)
    puts "Here, I can call any instance method" 
  end

  def sending_mail_for_you 
    puts "I am actually sending mail for you"
  end  

end
#notice, fake_method is not defined in the MyMailer class.
MyMailer.fake_method
This will give output: 
=> "Here, I can call any instance method"
"I am actually sending mail for you"

ActionMailer::Base 做的事情类似于上面的代码。 即使我们没有任何这样的方法称为 "fake_method" 仍然在执行 method_missing 部分时,它会在内部调用您的 'sending_mail_for_you' 方法。