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