简体   繁体   English

Ruby类与实例方法的混淆

[英]Ruby class vs instance method confusion

Given the 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

and the following test code: 以及以下测试代码:

c = Contact.new
UserMailer.contact_email(c)

How is it that this code works? 这段代码是如何工作的? I thought my contact_email was an instance method, but it is being invoked as a class method, and it works. 我认为我的contact_email是一个实例方法,但它作为一个类方法被调用,并且它可以工作。

thanks for your help - as I learn Ruby and Rails :) 感谢您的帮助 - 我学习Ruby和Rails :)

-mark -标记

You're entirely correct that this looks wrong at first glance. 乍一看,这看起来是错误的,这是完全正确的。

It works because there is a method_missing on the class ( see source ) that looks like this 它的工作原理是因为类上有一个method_missing参见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 is basically the names of the methods of your mailer that correspond to emails that can be sent, and MessageDelivery is a little proxy class that will eventually do action_methods基本上是邮件程序的名称,对应于可以发送的电子邮件,而MessageDelivery是一个小代理类,最终会做

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

Off the top of my head I'm not entirely sure why this is done this way, but the basic class method to instance method proxying has been around in one form or another since the very early days of actionmailer 在我的脑海中,我不完全确定为什么这样做是这样的,但实例方法代理的基本类方法已经以某种形式存在,因为动作管理器的早期阶段

Check 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

Sample implementation: 示例实施:

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 does something like above code. ActionMailer :: Base执行类似上面代码的操作。 Even we don't have any such method called "fake_method" still when the method_missing section is executed, it internally gives call to your 'sending_mail_for_you' method. 即使我们在执行method_missing部分时仍然没有任何名为"fake_method"方法,它在内部调用你的'sending_mail_for_you'方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM