You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:22:19