method_missing: неопределенный метод mail для Emailer: Class (NoMethodError) - PullRequest
0 голосов
/ 06 мая 2018

Я изучаю книгу Питера Купера 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

Как видите, я хочу использовать SMTP-сервер Yahoo для отправки электронного письма на мою учетную запись Gmail. Я предоставляю ActionMailer :: Base необходимые настройки smtp и создаю метод класса 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 не распознаются, поскольку оба метода принадлежат ActionMailer :: Base в Ruby 5.2.0.

--- отредактировано -
Если я удаляю self из метода test_email, как это было изначально в книге (я думал, что это было ошибкой), когда я запускаю файл 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 в отдельный набор гемов rvm и написал приведенный выше код в файле rb, код извлечен из книги. Запустив этот скрипт я получаю ошибку EOFError. Все мои попытки заставить его работать, такие как добавление self в метод test_email или вызов метода test_email в экземпляре класса Emailer, потерпели неудачу.

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

У меня не было учетной записи Yahoo, но эта конфигурация работала с моей учетной записью 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
0 голосов
/ 07 мая 2018

Проблема заключается в использовании «я». Должно быть

def test_email(email_address, email_body)
  ...
end

вместо

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

Итак, Emailer.test_email.deliver_now будет работать. В документах мы видим, что mail является методом экземпляра, но в self.method_name доступны только методы класса. Метод класса - это часть функциональности, которая принадлежит этому классу, но не привязана к какому-либо конкретному экземпляру. Обратное утверждение также справедливо. Почему Emailer экземпляр вместо класса? Это волшебство от ActionMailer :: Base

...