собственный способ отправки сообщений в ActionMailer

Не типичная ситуация, но вполне реальная. Заголовок не очень доходчиво объясняет то, что я тут изложу. Предположим, вы используете Devise и хотите заместо E-mail, которая по умолчанию является обязательным полем для пользователя, а также с помощью протокола SMTP которой происходит восстановление пароля и прочие фенечки, воспользоваться жаббером.

Короче говоря, после уточнений в офисе, ситуация такова: необходимо подменить способ отправки всех писем в Rails-приложений. Если обычно используется SMTP и сообщения являются обычными e-mail письмами, то тут будет рассматриваться случай когда письма являются сообщениями другого рода, например жаббер-сообщениями, а за место SMTP будет, соответственно, XMPP. Подменяться будут не какие-то отдельные сообщения в отдельно взятом экшене отдельного контроллера, а во всем приложении и сразу.

По началу я, будучи наивным юнцом, не знал, что в Rails предусмотрена возможность введения своего протокола отправки, и подумывал сделать так: с помощью mini-smtp-server, который бы я встроил в rake-фаил и на который бы настроил приложение, поднять SMTP-сервер, в котором уже и устроить подмену SMTP на нужный мне способ. Но судьба сложилась иначе и звезды указали мне путь на ActionMailer::Base.add_delivery_method.

Основу для данной инструкции я украл отсюда, однако от приведенной в посте инструкции ваша радость была бы неполной без горького шоколада “Россия”, т.к. досконально выполнив все что там сказано, можно наблюдать:

$ rails c
Loading development environment (Rails 4.0.0)
2.0.0p247 :001 > User.first.send_reset_password_instructions
  User Load (29.6ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
  User Load (74.5ms)  SELECT `users`.* FROM `users` WHERE `users`.`reset_password_token` = '59c1c232f95e7a96c4ac735b8fd899b5d993b07f7261a9551c68280ceb443577' LIMIT 1
   (0.2ms)  BEGIN
  SQL (101.3ms)  UPDATE `users` SET `reset_password_token` = '59c1c232f95e7a96c4ac735b8fd899b5d993b07f7261a9551c68280ceb443577', `reset_password_sent_at` = '2014-08-22 02:18:36', `updated_at` = '2014-08-22 02:18:36' WHERE `users`.`id` = 1
   (297.8ms)  COMMIT
ArgumentError: wrong number of arguments (1 for 0)
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/mail-2.5.4/lib/mail/message.rb:257:in `initialize'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/mail-2.5.4/lib/mail/message.rb:257:in `new'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/mail-2.5.4/lib/mail/message.rb:257:in `delivery_method'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionmailer-4.0.0/lib/action_mailer/delivery_methods.rb:66:in `wrap_delivery_behavior'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionmailer-4.0.0/lib/action_mailer/delivery_methods.rb:80:in `wrap_delivery_behavior!'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionmailer-4.0.0/lib/action_mailer/base.rb:684:in `mail'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/devise-3.1.1/lib/devise/mailers/helpers.rb:16:in `devise_mail'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/devise-3.1.1/app/mailers/devise/mailer.rb:11:in `reset_password_instructions'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/abstract_controller/base.rb:189:in `process_action'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/abstract_controller/callbacks.rb:18:in `block in process_action'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:373:in `_run__3933474617966347476__process_action__callbacks'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/activesupport-4.0.0/lib/active_support/callbacks.rb:80:in `run_callbacks'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/abstract_controller/callbacks.rb:17:in `process_action'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/abstract_controller/base.rb:136:in `process'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/abstract_controller/rendering.rb:44:in `process'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionmailer-4.0.0/lib/action_mailer/base.rb:503:in `process'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionmailer-4.0.0/lib/action_mailer/base.rb:497:in `initialize'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionmailer-4.0.0/lib/action_mailer/base.rb:480:in `new'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/actionmailer-4.0.0/lib/action_mailer/base.rb:480:in `method_missing'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/devise-3.1.1/lib/devise/models/authenticatable.rb:175:in `send_devise_notification'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/devise-3.1.1/lib/devise/models/recoverable.rb:54:in `send_reset_password_instructions'
        from (irb):1
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands/console.rb:90:in `start'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start'
        from /usr/local/rvm/gems/ruby-2.0.0-p247/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'2.0.0p247 :002 >

Поэтому я перескажу все от начала и до конца с учетом поправки косяка, который не заметил Arun Kumar Singh (так зовут перца, который ведет этот codedecoder.wordpress.com), при этом мой новый способ отправки будет XMPP.

свой класс со способом отправки

Создаем файл lib/xmpp_delivery.rb с классом, который будет содержать новый способ доставки.

class XMPPDelivery
 
  def initialize(opts={})
    @settings=opts
  end
 
  def deliver!(message)
      #тут как бы горы кода по отправки сообщений в жабу
      if xmpp.deliver!(@settings)
        p message
        true
      else false end
  end
 
end

Ошибка Codedecoder’а исправляется уже на этом этапе – он забыл копипастнуть в листинг приведенного им модуля, метод initialize с одним обязательным параметром, который указывается в /usr/local/rvm/gems/ruby-2.0.0-p247/gems/mail-2.5.4/lib/mail/message.rb:257.

подключение нового класса

Далее в config/environment.rb необходимо подключить созданный файл:

# Load the Rails application.
require File.expand_path('../application', __FILE__)
 
require 'xmpp_delivery.rb'
 
# Initialize the Rails application.
PsakiSpeechCreator::Application.initialize!

объявление нового способа

Теперь надо добавить инициатор config/initializers/mailer.rb, в котором будет торжественно объявляться новый способ:

ActionMailer::Base.add_delivery_method :xmpp, XMPPDelivery

настройка на новый способ

И в конце, в настройках нужной среды (например в config/environments/development.rb), указать способ как основной:

...
  config.action_mailer.default_url_options = { :host => 'localhost'}
  config.action_mailer.delivery_method = :xmpp
...

А если кому-то серьезно надоел e-mail в Devise и он хочет сделать отправку в жабу, то вам пригодится гем xmpp4r-simple, ошибки которого были замечены тут и тут.

No Comments.

Leave a Reply

(обязательно)

(обязательно)