Rails中ActionView在delayed_job调用时因I18n.fallbacks崩溃的修复方法
Rails 4 + Delayed Job 邮件发送 TypeError 问题修复
问题场景
我在Rails 4应用里用Delayed Job发送邮件,控制台执行了:
ActionMailer::Base.mail(from: 'mail@example.com', to: 'foo@example.com', subject: 'test', body: "Hello, you've got mail!").deliver_later
本地触发任务时用:
Delayed::Job.last.invoke_job
结果任务崩溃,报错:
Devise::Mailer#invitation_instructions: processed outbound mail in 56234.1ms Performed ActionMailer::DeliveryJob from DelayedJob(mailers) in 56880.04ms TypeError: no implicit conversion of nil into Array from /Users/de/.rvm/gems/ruby-2.4.0/gems/actionview-4.2.10/lib/action_view/lookup_context.rb:51:in `concat' from /Users/de/.rvm/gems/ruby-2.4.0/gems/actionview-4.2.10/lib/action_view/lookup_context.rb:51:in `block in <class:LookupContext>' from /Users/de/.rvm/gems/ruby-2.4.0/gems/actionview-4.2.10/lib/action_view/lookup_context.rb:39:in `initialize_details' from /Users/de/.rvm/gems/ruby-2.4.0/gems/actionview-4.2.10/lib/action_view/lookup_context.rb:205:in `initialize' ...
排查后发现问题出在ActionView的lookup_context.rb第51行:
register_detail(:locale) do locales = [I18n.locale] locales.concat(I18n.fallbacks[I18n.locale]) if I18n.respond_to? :fallbacks # 此处崩溃 end
调试信息显示:
I18n.locale=>:deI18n.fallbacks=>{:en=>[]}
因为I18n.fallbacks[:de]返回nil,调用concat时试图把nil转成数组,就抛出了TypeError。
问题原因
你的I18n fallback配置里没有包含:de这个语言区域,当代码尝试获取:de的fallback列表时,返回了nil,而Array#concat只接受数组参数,无法处理nil,所以触发了类型转换错误。
修复方案
方法1:配置全局I18n Fallbacks
在config/application.rb或者专门的I18n配置文件(比如config/initializers/i18n.rb)里添加fallback配置:
# config/initializers/i18n.rb I18n.default_locale = :de # 如果你的默认语言是德语 I18n.fallbacks.map(:de => :en) # 或者更通用的配置,让所有非en的语言都fallback到en I18n.fallbacks = I18n::Locale::Fallbacks.new(:de => :en, :fr => :en, :es => :en)
这样当:de没有对应的翻译时,会自动 fallback 到:en,同时I18n.fallbacks[:de]会返回[:en]而不是nil。
方法2:设置默认Fallback规则
如果你希望所有未配置的语言都fallback到默认语言,可以用更简洁的写法:
# config/initializers/i18n.rb I18n.default_locale = :de I18n.fallbacks.defaults = [I18n.default_locale, :en]
或者直接启用全局fallback到默认语言:
I18n.fallbacks = true
这会让任何语言的fallback列表都包含默认语言。
方法3:临时调试(适合开发环境)
如果只是开发环境临时测试,可以在控制台里先手动设置fallback:
I18n.fallbacks[:de] = [:en]
然后再触发Delayed Job任务,确认问题解决后再把配置写到初始化文件里。
验证修复
配置完成后,重启Rails服务器和Delayed Job进程,然后重新执行邮件发送和任务触发命令,检查是否还会出现TypeError。同时可以在控制台验证:
I18n.fallbacks[:de] # 应该返回[:en]或者包含:en的数组,而不是nil
内容的提问来源于stack exchange,提问作者de.
相关产品推荐
相关产品推荐

