Sidekiq + Devise Mailer有多个子域名

Mat*_*ias 5 devise sidekiq ruby-on-rails-4 devise-async

我在我的一个项目中在运行时更改ActionMailer :: Base.default_url_options = {:host => host}时遇到问题.

设置:我有多个子域,它们在后端使用相同的Rails-Application.我想通过Sidekiq队列将我的Devise邮件发送给用户.设计邮件(确认,重置密码)包含链接,这些链接需要特定的子域才是正确的.

我的环境

rails (4.2.0)
sidekiq (3.3.1)
devise (3.4.1)
devise-async (0.9.0)
Run Code Online (Sandbox Code Playgroud)

我的application_controller中有一个before_action

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
Run Code Online (Sandbox Code Playgroud)

现在,如果我想重置密码,我总是会得到我在环境文件中指定的默认网址选项.如果我从我的环境中删除default_url_options,我会在sidekiq日志中获得默认的Devise错误.

ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
Run Code Online (Sandbox Code Playgroud)

主机始终在控制器中正确设置.我已经调试过了.似乎主机没有传递给sidekiq ..任何想法如何解决这个问题?

我无法在某个地方保存子域名,因为用户可以触发来自不同子域的电子邮件,但并不总是相同.我需要一种方法告诉Devise应该使用哪个主机发送特定的电子邮件.我可以覆盖Devise邮件程序并传递主机或类似的东西吗?

在我的情况下,以下解决方案是不可能的: 使用sidekiq时Rails动作邮件程序中的动态域名

顺便说一句:完整的工作流程,包括设计,设计 - 异步和sidekiq本身(在开发,分期和生产中).只有链接的主机不正确 - >这是我的大问题:-) ..

Mat*_*ias 1

我最终得到了以下解决方案。此解决方案包含您有多个客户的情况,并且这些客户可以拥有自己的电子邮件设置和邮件中 URL 的自己的域/子域。

我使用了自己的邮件程序类并迷上了客户可能的自定义电子邮件设置:

配置/初始化器/devise.rb:

config.mailer = "DeviseMailer"
Run Code Online (Sandbox Code Playgroud)

配置/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
Run Code Online (Sandbox Code Playgroud)

应用程序/mailers/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
Run Code Online (Sandbox Code Playgroud)

更改电子邮件视图模板中的 URL:

应用程序/视图/设计/邮件程序/confirmation_instructions.html.erb

只需使用新的 url-options 更改链接即可。

应用程序/视图/设计/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 %>
Run Code Online (Sandbox Code Playgroud)

这是我的解决方案......如果您有任何问题,请告诉我。

编辑: 不要忘记在您的环境中设置默认的 url 选项。例如在你的development.rb - config/environments/development.rb中:

config.action_mailer.default_url_options = { host: "your-host.dev", port: 3000 }
Run Code Online (Sandbox Code Playgroud)