【问题标题】:Storing current optional route scope before calling deliver_later on rails mailer在rails mailer上调用deliver_later之前存储当前的可选路由范围
【发布时间】:2016-12-05 04:07:25
【问题描述】:

导轨 4.2 红宝石 2.3

我有两个与区域设置信息相关的可选路由范围。它们在配置 default_url_options 方法的application_controller 中的before_action 中设置。即

# app/controllers/application_controller
# simplified version, usually has two locale values, 
# locale_lang and locale_city


before_action :redirect_to_locale_unless_present

private

# If params[:locale] is not set then
# redirect to the correct locale base on request data    
def redirect_to_locale_unless_present
  unless params[:locale].present?
    redirect_to url_for(locale: request.location.country_code)
  end
end

def default_url_options(options = {}
  { locale_lang: params[:locale_lang] }.merge(options)
end

范围是 locale_langlocale_city 最终看起来像 http://localhost:3000/fr/http://localhost:3000/en/

这一切都在浏览器中按预期工作,但是我想利用 ActionMailer::DeliveryJob 在后台进程中发送电子邮件。明显的问题是 ActionMailer::DeliveryJob 不存储 params[:locale] 的值。

我希望能够调用SomeMailer.generic_email(options).deliver_later 并将当前的default_url_options 发送到ActionMailer::DeliveryJob,然后它将沿着链传递并在实际处理邮件时使用它们。我当然可以将 default_url_options 定义为每个 Mailer 方法的参数,但我更愿意将应用程序设置为自动包含在内。

您是否遇到过此问题或对如何处理任务有任何建议。请记住,它也应该是线程安全的。

我目前失败的方法是将当前 request 保存在 Thread.current 中,然后在通过 调用 enqueue_delivery 时检索它们.deliver_later。然后我想重写 ActionMailer::DeliveryJobperform 方法来接受 url_options 并使用 class_eval 来定义当前邮件程序类中的 default_url_options 方法。 但是,使用 Deliver_later 时似乎甚至没有调用 perform 任何想法?

class ApplicationController
  before_action :store_request

  private

  def store_request
    Thread.current['actiondispatch.request'] = request
  end
end

module DeliverLaterWithLocale
  module MessageDeliveryOverrides
    def enqueue_delivery(delivery_method, options={})
      args = [
        @mailer.name,
        @mail_method.to_s,
        delivery_method.to_s,
        url_options,
        *@args
      ]
      ActionMailer::DeliveryJob.set(options).perform_later(*args)
    end

    private

    def url_options
      options = {}
      request  = Thread.current["actiondispatch.request"]
      if request
        host     = request.host
        port     = request.port
        protocol = request.protocol
        lang = request.params[:locale_lang]
        city = request.params[:locale_city]
        standard_port = request.standard_port
        options[:protocol] = protocol
        options[:host]     = host
        options[:port]     = port if port != standard_port
        options[:locale_lang] = lang
        options[:locale_city] = city
      end
      ActionMailer::Base.default_url_options.merge(options)
    end
  end

  module DeliveryJobOverrides
    def perform(mailer, mail_method, delivery_method, url_options, *args)
      mailer = mailer.constantize.public_send(mail_method, *args)
      Kernel.binding.pry
      mailer.class_eval <<-RUBY, __FILE__, __LINE__ + 1
        def default_url_options_with_options(*args)
          default_url_options_without_current_request(*args).merge(url_options)
        end
        alias_method_chain :default_url_options, :options
      RUBY
      mailer.send(delivery_method)
    end
  end
end

【问题讨论】:

    标签: ruby-on-rails locale actionmailer delayed-job rails-activejob


    【解决方案1】:

    以防其他人想要这样做。我通过添加来修复它

    class ApplicationController
      before_action :store_request
    
      private
    
      def store_request
        Thread.current['actiondispatch.request'] = request
      end
    end
    
    module DeliverLaterWithLocale
      module MessageDeliveryOverrides
        def enqueue_delivery(delivery_method, options={})
          args = [
            @mailer.name,
            @mail_method.to_s,
            delivery_method.to_s,
            url_options,
            *@args
          ]
          ActionMailer::DeliveryJob.set(options).perform_later(*args)
        end
    
        private
    
        def url_options
          options = {}
          request  = Thread.current["actiondispatch.request"]
          if request
            host     = request.host
            port     = request.port
            protocol = request.protocol
            lang = request.params[:locale_lang]
            city = request.params[:locale_city]
            standard_port = request.standard_port
            options[:protocol] = protocol
            options[:host]     = host
            options[:port]     = port if port != standard_port
            options[:locale_lang] = lang
            options[:locale_city] = city
          end
          ActionMailer::Base.default_url_options.merge(options)
        end
      end
    
      module DeliveryJobOverrides
        def perform(mailer, mail_method, delivery_method, url_options, *args)
          mailer = mailer.constantize
          mailer.default_url_options = url_options
          mailer.public_send(mail_method, *args).send(delivery_method)
        end
      end
    end
    

    然后将这些添加到初始化程序中的各个类

    【讨论】:

      猜你喜欢
      • 2018-09-05
      • 1970-01-01
      • 1970-01-01
      • 2012-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-18
      • 2014-05-26
      • 2022-11-26
      相关资源
      最近更新 更多