如何在使用ActiveJob/SuckerPunch发送延迟邮件时传递Locale?
嘿,这个场景我之前也碰到过,要给延迟任务传递Locale其实挺简单的,给你俩实用的方案:
方案1:直接把当前Locale作为参数传给Job
因为Locale是字符串,属于ActiveJob可序列化的参数类型,直接传就行。
先修改控制器,把请求时的Locale一起传给Job:
# app/controllers/users_controller.rb class UsersController < ApplicationController def activate user = User.find_by(:activation_token => params[:id]) user.activate # 把当前请求的locale作为参数传递 SendFollowUpEmailJob.perform_in(30, user, I18n.locale) sign_in user end end
然后在Job里接收这个参数,用I18n.with_locale临时切换语言环境(这个方法是线程安全的,不会污染其他任务):
# app/jobs/send_follow_up_email.rb class SendFollowUpEmailJob < ActiveJob::Base include SuckerPunch::Job queue_as :default def perform(user, locale) # 临时切换到指定locale,执行完自动恢复原设置 I18n.with_locale(locale) do # 注意这里用deliver_now!因为你已经在SuckerPunch的异步任务里了,再用deliver_later会多套一层异步,没必要 SupportMailer.follow_up(user).deliver_now end end end
方案2:把Locale存在用户模型里(更优雅的持久化方式)
如果你的用户有自定义语言偏好,直接把Locale存在User表的字段里,这样不用每次传参数,Job直接读取用户的偏好即可。
第一步先加个数据库字段:
# 生成迁移文件 rails generate migration AddLocaleToUsers locale:string # 执行迁移 rails db:migrate
然后在用户创建或更新时,把当前Locale保存到用户模型(比如注册或语言设置页面):
# 示例:用户注册时保存locale def create @user = User.new(user_params) @user.locale = I18n.locale # 把当前请求的locale存进去 if @user.save # ... 后续逻辑 end end
最后修改Job,直接用用户的Locale(没有的话 fallback到默认语言):
# app/jobs/send_follow_up_email.rb class SendFollowUpEmailJob < ActiveJob::Base include SuckerPunch::Job queue_as :default def perform(user) # 优先用用户的locale,没有就用系统默认 I18n.with_locale(user.locale || I18n.default_locale) do SupportMailer.follow_up(user).deliver_now end end end
重要提醒
千万别直接用I18n.locale = locale全局设置语言!因为SuckerPunch用的是线程池,线程会被多个任务复用,全局设置会导致后续任务的Locale被错误覆盖。I18n.with_locale块是最安全的方式,它会在块执行完自动恢复线程原来的Locale设置。
内容的提问来源于stack exchange,提问作者Tintin81
相关产品推荐
相关产品推荐

