0

的Rails 4.2 紅寶石2.3調用deliver_later之前保存當前的可選路徑範圍軌郵件

我有兩個可選路由與區域信息範圍。它們在配置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方法的參數,但我更願意設置應用程序,以便它自動包含在內。

你有沒有遇到過這個問題,或對如何處理任務有任何建議。請記住,它也應該是線程安全的。

我目前沒有辦法是保存當前請求Thread.current,然後檢索這些時enqueue_delivery通過.deliver_later被調用。然後我想重寫的ActionMailer :: DeliveryJob執行方法接受url_options和使用class_eval定義default_url_options的當前郵件類方法。 然而,使用deliver_later任何想法時,似乎甚至不會調用執行?

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 

回答

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 

,然後在初始化預先準備這些各個類別