Ruby类与实例方法的混淆

时间:2015-01-13 19:02:07

标签: ruby-on-rails ruby learn-ruby-on-rails

鉴于课程:

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是一个实例方法,但它作为一个类方法被调用,并且它可以工作。

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

-mark

2 个答案:

答案 0 :(得分:5)

乍一看,这看起来是错误的,这是完全正确的。

它有效,因为有一个method_missing 在类(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是一个最终会做的小代理类

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

脱离我的头脑我不完全确定为什么这样做是这样的,但实例方法代理的基本类方法已经以某种形式存在,因为动作管理器的早期版本

答案 1 :(得分:0)

检查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执行类似上面代码的操作。 即使我们在执行method_missing部分时仍然没有任何名为"fake_method"的方法,它在内部会调用您的'sending_mail_for_you'方法。