【问题标题】:`method_missing': undefined method `mail' for Emailer:Class (NoMethodError)`method_missing':Emailer:Class (NoMethodError) 的未定义方法 `mail'
【发布时间】:2018-10-16 11:39:42
【问题描述】:

我正在研究 Peter Cooper 的《Beginning Ruby》一书。
其中有一个使用 ActionMailer 发送电子邮件的简单示例。 示例代码如下:

require 'action_mailer'

ActionMailer::Base.smtp_settings = {
    :address => "smtp.mail.yahoo.com",
    :port => 465,
    :authentication => :login,
    :user_name => "username@yahoo.com",
    :password => "password",
    :openssl_verify_mode => :ssl
}

class Emailer < ActionMailer::Base
  def self.test_email(email_address, email_body)
    mail(to: email_address, from: 'username@yahoo.com', subject: 'action mailer test', body: email_body)
  end
end

Emailer.test_email('username@gmail.com', 'This is a test e-mail!').deliver_now

如您所见,我想使用 yahoo 的 smtp 服务器向我的 gmail 帐户发送电子邮件。我向 ActionMailer::Base 提供所需的 smtp setting 并创建类方法 test_email 以使用 main 方法和 deliver_now 方法发送电子邮件。但是我收到以下错误消息:

/home/asarluhi/.rvm/gems/ruby-2.5.1@beginning_ruby/gems/actionmailer-5.2.0/lib/action_mailer/base.rb:582:in `method_missing': undefined method `mail' for Emailer:Class (NoMethodError)

我还尝试将test_email 方法更改为实例方法并使用Emailer.new.test_email...在这种情况下,我收到的错误消息是:

/home/asarluhi/.rvm/gems/ruby-2.5.1@beginning_ruby/gems/mail-2.7.0/lib/mail/message.rb:1396:in `method_missing': undefined method `deliver_now' for #<Mail::Message:0x0000000002e0eac8> (NoMethodError)

我不知道为什么方法 mail 首先是方法 deliver_now 不被识别,而是在 Ruby 5.2.0 中属于 ActionMailer::Base 的两个方法。

--- 已编辑 --
如果我从test_email 方法中删除self,因为它最初是在书中(我认为这是一个错误),当我运行包含上述代码的 rb 文件时,我会收到一个很长的回溯(21行)以下错误信息:

/home/asarluhi/.rvm/rubies/ruby-2.5.1/lib/ruby/2.5.0/net/protocol.rb:189:in `rbuf_fill': end of file reached (EOFError)

据作者介绍,ActionMailer 可以独立于 Rails 使用。 所以我将 ActionMailer gem 安装在一个专用的 rvm gemset 中,并将上面的代码写在一个rb 文件中,代码摘自书中。运行此脚本我收到 EOFError 错误。我所有使其工作的尝试,例如将self 添加到test_email 方法或在Emailer 类的实例上调用方法test_email 都失败了。

【问题讨论】:

  • 我猜你应该让test_email 方法成为Emailer 类的实例方法,而不是它的单例方法。
  • 试试deliver,据我所知,这在 Rails 5 中有所改变。
  • @Asarluhi:将其设为实例方法,但将其作为类方法调用。 Action mailer 类就是这么奇怪。
  • @Asarluhi:你在编辑文件时搞砸了。检查每个开头关键字(classdef 等)是否有一个 end
  • @AsarluhiI:如果您的邮件类是有效的,那么它就是视图(或其他东西)。结局肯定是不平衡的某处

标签: ruby-on-rails ruby actionmailer


【解决方案1】:

问题在于使用“自我”。必须是

def test_email(email_address, email_body)
  ...
end

而不是

def self.test_email(email_address, email_body)
  ...
end

所以,Emailer.test_email.deliver_now 会起作用。在docs 中,我们可以看到mail 是实例方法,但在self.method_name 中只有类方法可用。类方法是属于该类但不绑定到任何特定单个实例的功能。相反的陈述也是公平的。 为什么Emailer 是实例而不是类?这是来自 ActionMailer::Base 的魔法

【讨论】:

  • “但 test_email 是该类的初始化程序” - 但事实并非如此。 “初始化程序”在 ruby​​ 中具有特定的含义。不过,那里肯定有一些魔力。
  • 另外,Emailer.test_email 返回 ActionMailer::MessageDelivery,而不是 Emailer
  • 是的,你说得对,那不是初始化程序并返回特定对象(来自方法 mail)Mail::Message。
  • @Leo 你是对的,这就是原始代码的编写方式,但它仍然无法正常工作,因为我收到了一个带有长回溯(21 行)的end of file reached (EOFError)。有什么问题我看不到
【解决方案2】:

没有要查看的 yahoo 帐户,但 this configuration 已使用我的 gmail 帐户:

require 'action_mailer'

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
    :address => "smtp.gmail.com",
    :port => 587,
    :authentication => :plain,
    :user_name => "sender@gmail.com",
    :password => "<password>",
    :enable_starttls_auto => true
}


class Emailer < ActionMailer::Base
  def test_email(email_address, email_body)
    mail(to: email_address, from: 'sender@gmail.com', subject: 'action mailer test', body: email_body)
  end
end

Emailer.test_email('recipient@gmail.com', 'This is a test e-mail!').deliver_now

【讨论】:

  • 显然对于 yahoo 来说,必须使用端口 587 和 :enable_starttls_auto =&gt; true:通过这些更改现在它可以工作了。我也有一个 gmail 帐户,但我收到了 Net::SMTPAuthenticationError 并在我的收件箱中收到了有关来自应用程序的被阻止登录尝试的通知,这可能会使我的帐户处于危险之中。他们说我可以通过允许访问不太安全的应用程序来继续使用这个应用程序,但这可能会使我的帐户容易受到攻击。
【解决方案3】:

可能导致此错误消息的一种方法是,如果您只是使用了错误的命名空间,例如我有

AlertsMailer.new_user_signup(user).deliver_now

但对我来说应该是

MessagesMailer.new_user_signup(user).deliver_now

所以 rails 找不到该命名空间的方法。据我所知,仔细检查您的代码是值得的 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-28
    • 1970-01-01
    • 2013-04-24
    • 2015-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多