Sidekiq + Devise Mailer с несколькими поддоменами

У меня проблема с изменением ActionMailer::Base.default_url_options = {:host => host} во время выполнения в одном из моих проектов.

Установка: у меня есть несколько поддоменов, которые используют одно и то же Rails-приложение в бэкэнде. Я хочу отправлять пользователям письма через Devise через очередь Sidekiq. Письма Devise (подтверждение, сброс пароля) содержат ссылки, и эти ссылки нуждаются в правильном указании субдомена.

Моя среда

rails (4.2.0)
sidekiq (3.3.1)
devise (3.4.1)
devise-async (0.9.0)

У меня есть before_action в моем application_controller

class ApplicationController < ActionController::Base

  before_action :set_action_mailer_default_url_options

  private

  def set_action_mailer_default_url_options
    host = "my-logic-to-get-the-correct-host"
    ActionMailer::Base.default_url_options = {:host => host}
  end

end

Теперь, если я хочу сбросить свой пароль, я всегда получаю параметры URL по умолчанию, которые я указал в файле сред. Если я удаляю default_url_options из моей среды, я получаю ошибку Devise по умолчанию в моих журналах sidekiq.

ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true

Хост всегда правильно установлен в контроллере. Я уже отладил это. Кажется, что хост не передан sidekiq.. Есть идеи, как я могу это исправить?

Я не могу сохранить поддомен где-нибудь, потому что пользователь может инициировать электронные письма из разных поддоменов и не всегда одинаковы. Мне нужен способ сообщить Devise, какой хост следует использовать для отправки определенного электронного письма. Могу ли я переопределить почтовую программу Devise и передать хост или что-то подобное?

Следующее решение невозможно в моем случае: динамическое доменное имя в Rails action mailer при использовании sidekiq

Кстати: полный рабочий процесс с devise, devise-async и sidekiq сам по себе работает (в разработке, постановке и производстве). Неправильно только хост ссылок -> и это моя большая проблема:-)..

2 ответа

Решение

Я оказался в следующем решении. Это решение содержит случай, когда у вас есть несколько клиентов, и у этих клиентов могут быть собственные настройки электронной почты и собственные домены / субдомены для URL-адресов в письмах.

Я использовал собственный класс почтовой программы и подключил возможные пользовательские настройки электронной почты клиента:

конфиг / Инициализаторы / devise.rb:

config.mailer = "DeviseMailer"

конфиг / secrets.yml:

development:
  mailer_settings:
    customers:
      customer_1_identifier_name:
        send:
          address: "smtp.gmail.com"
          port: 587
          domain: "example"
          user_name: "test@example.com"
          email: "noreply@example.com"
          password: "secret"
          authentication: "plain" # or "login"
          ssl: false # or true
          tls: false # or true
          enable_starttls_auto: true # or false

Приложение / отправители / devise_mailer.rb:

class DeviseMailer < Devise::Mailer
  layout 'mailer'

  after_action :set_email_settings_and_sender, only: [:reset_password_instructions, :confirmation_instructions]

  def reset_password_instructions(record, token, opts={})
    @account = record.current_account if record.class == User # set the account of current_user - current_account is an own helper method
    super
  end

  def confirmation_instructions(record, token, opts={})
    @account = record.current_account if record.class == User && record.unconfirmed_email.present?
    super
  end

  private

    # re-set the email settings for the given user and his account:
    def set_email_settings_and_sender
      if @account.present? && @account.custom_email_settings?
        mail.reply_to = nil
        settings = Rails.application.secrets.mailer_settings["customers"][@account.identifier_name]["send"].symbolize_keys
        mail.delivery_method.settings.merge!(settings)
        mail.from = "#{@account.display_name} <#{settings[:email]}>"
      end
    end

end

Измените URL в шаблонах представления электронной почты:

приложение / просмотров / изобрести / почтовик / confirmation_instructions.html.erb

Просто измените ссылку с новыми URL-опциями.

приложение / просмотров / изобрести / reset_password_instructions.html.erb

<% if @account.present? && @account.domain.present? %>
  <% link = "#{@account.host_for_links}/auth/password/edit?reset_password_token=#{@token}" %>
  <a href="<%= link %>"><%= link %></a>
<% else %>
  <a href="<%= edit_password_url(@resource, reset_password_token: @token) %>"><%= edit_password_url(@resource, reset_password_token: @token) %></a>
<% end %>

Это было мое решение.. если у вас есть какие-либо вопросы, просто дайте мне знать.

РЕДАКТИРОВАТЬ: Не забудьте установить параметры URL по умолчанию в вашей среде. Например, в вашем файле development.rb - config / environment / development.rb:

config.action_mailer.default_url_options = { host: "your-host.dev", port: 3000 }

Вы можете перезаписать ваши параметры URL по умолчанию, как это в вашем ApplicationController:

http://edgeguides.rubyonrails.org/action_controller_overview.html

class ApplicationController < ActionController::Base
  def default_url_options
    {:host => host}
  end
end

ИЛИ вы можете попробовать этот ответ: /questions/8863395/kak-ustanovit-configactioncontrollerdefaulturloptions-host-dlya-kazhdoj-sredyi/8863420#8863420

Другие вопросы по тегам