diff options
author | Johannes Opper <johannes.opper@gmail.com> | 2015-07-07 21:52:28 +0200 |
---|---|---|
committer | Johannes Opper <johannes.opper@gmail.com> | 2015-08-04 00:38:18 +0200 |
commit | 3860e6b2bf486d8b27d433daab358dbc68ae3448 (patch) | |
tree | 136f0b6e7cfeac3ef48ea1c41c37332083dba8d2 | |
parent | e598967548114da4f8d85070584460108a7305ff (diff) | |
download | rails-3860e6b2bf486d8b27d433daab358dbc68ae3448.tar.gz rails-3860e6b2bf486d8b27d433daab358dbc68ae3448.tar.bz2 rails-3860e6b2bf486d8b27d433daab358dbc68ae3448.zip |
Fixes #20799
When `#perform_later` is called the locale isn't stored on the
queue, which results in a locale reset when the job is performed.
An example of the problem:
I18n.locale = 'de'
HelloJob.perform_now # german message, correct
but
I18n.locale = 'de'
HelloJob.perform_later # english message, incorrect
This PR attaches the current I18n.locale to every job during the
serialization process. It is then restored during deserialization
and used to perform the job with the correct locale.
It falls back to the default locale if no serialized locale is
found in order to provide backward compatibility with previously
stored jobs. It is not necessary to clear the queue for the update.
-rw-r--r-- | activejob/CHANGELOG.md | 7 | ||||
-rw-r--r-- | activejob/lib/active_job/base.rb | 2 | ||||
-rw-r--r-- | activejob/lib/active_job/core.rb | 7 | ||||
-rw-r--r-- | activejob/lib/active_job/translation.rb | 11 | ||||
-rw-r--r-- | activejob/test/cases/job_serialization_test.rb | 16 | ||||
-rw-r--r-- | activejob/test/cases/translation_test.rb | 20 | ||||
-rw-r--r-- | activejob/test/integration/queuing_test.rb | 17 | ||||
-rw-r--r-- | activejob/test/jobs/translated_hello_job.rb | 10 | ||||
-rw-r--r-- | activejob/test/support/integration/dummy_app_template.rb | 6 | ||||
-rw-r--r-- | activejob/test/support/integration/test_case_helpers.rb | 4 | ||||
-rw-r--r-- | guides/source/active_job_basics.md | 13 |
11 files changed, 111 insertions, 2 deletions
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md index c523723fc4..1bd97eed38 100644 --- a/activejob/CHANGELOG.md +++ b/activejob/CHANGELOG.md @@ -1,3 +1,10 @@ +* Include I18n.locale into job serialization/deserialization and use it around + `perform`. + + Fixes #20799. + + *Johannes Opper* + * Allow `DelayedJob`, `Sidekiq`, `qu`, and `que` to report the job id back to `ActiveJob::Base` as `provider_job_id`. diff --git a/activejob/lib/active_job/base.rb b/activejob/lib/active_job/base.rb index fd49b3fda5..5d7c4cfb91 100644 --- a/activejob/lib/active_job/base.rb +++ b/activejob/lib/active_job/base.rb @@ -5,6 +5,7 @@ require 'active_job/enqueuing' require 'active_job/execution' require 'active_job/callbacks' require 'active_job/logging' +require 'active_job/translation' module ActiveJob #:nodoc: # = Active Job @@ -60,6 +61,7 @@ module ActiveJob #:nodoc: include Execution include Callbacks include Logging + include Translation ActiveSupport.run_load_hooks(:active_job, self) end diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb index 0528572cd0..eac7279309 100644 --- a/activejob/lib/active_job/core.rb +++ b/activejob/lib/active_job/core.rb @@ -20,6 +20,9 @@ module ActiveJob # ID optionally provided by adapter attr_accessor :provider_job_id + + # I18n.locale to be used during the job. + attr_accessor :locale end # These methods will be included into any Active Job object, adding @@ -68,7 +71,8 @@ module ActiveJob 'job_class' => self.class.name, 'job_id' => job_id, 'queue_name' => queue_name, - 'arguments' => serialize_arguments(arguments) + 'arguments' => serialize_arguments(arguments), + 'locale' => I18n.locale } end @@ -96,6 +100,7 @@ module ActiveJob self.job_id = job_data['job_id'] self.queue_name = job_data['queue_name'] self.serialized_arguments = job_data['arguments'] + self.locale = job_data['locale'] || I18n.locale end private diff --git a/activejob/lib/active_job/translation.rb b/activejob/lib/active_job/translation.rb new file mode 100644 index 0000000000..67e4cf4ab9 --- /dev/null +++ b/activejob/lib/active_job/translation.rb @@ -0,0 +1,11 @@ +module ActiveJob + module Translation #:nodoc: + extend ActiveSupport::Concern + + included do + around_perform do |job, block, _| + I18n.with_locale(job.locale, &block) + end + end + end +end diff --git a/activejob/test/cases/job_serialization_test.rb b/activejob/test/cases/job_serialization_test.rb index db22783030..e23380a7bf 100644 --- a/activejob/test/cases/job_serialization_test.rb +++ b/activejob/test/cases/job_serialization_test.rb @@ -12,4 +12,20 @@ class JobSerializationTest < ActiveSupport::TestCase GidJob.perform_later @person assert_equal "Person with ID: 5", JobBuffer.last_value end + + test 'serialize includes current locale' do + assert_equal :en, HelloJob.new.serialize['locale'] + end + + test 'deserialize sets locale' do + job = HelloJob.new + job.deserialize 'locale' => :es + assert_equal :es, job.locale + end + + test 'deserialize sets default locale' do + job = HelloJob.new + job.deserialize({}) + assert_equal :en, job.locale + end end diff --git a/activejob/test/cases/translation_test.rb b/activejob/test/cases/translation_test.rb new file mode 100644 index 0000000000..d5e3aaf9e3 --- /dev/null +++ b/activejob/test/cases/translation_test.rb @@ -0,0 +1,20 @@ +require 'helper' +require 'jobs/translated_hello_job' + +class TranslationTest < ActiveSupport::TestCase + setup do + JobBuffer.clear + I18n.available_locales = [:en, :de] + @job = TranslatedHelloJob.new('Johannes') + end + + teardown do + I18n.available_locales = [:en] + end + + test 'it performs the job in the given locale' do + @job.locale = :de + @job.perform_now + assert_equal "Johannes says Guten Tag", JobBuffer.last_value + end +end diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb index d345092dee..e1634972d1 100644 --- a/activejob/test/integration/queuing_test.rb +++ b/activejob/test/integration/queuing_test.rb @@ -68,4 +68,21 @@ class QueuingTest < ActiveSupport::TestCase refute delayed_test_job.provider_job_id.nil?, 'Provider job id should by set for delayed jobs by provider' end + + test 'current locale is kept while running perform_later' do + skip if adapter_is?(:inline) + + begin + I18n.available_locales = [:en, :de] + I18n.locale = :de + + TestJob.perform_later @id + wait_for_jobs_to_finish_for(5.seconds) + assert job_executed + assert_equal 'de', job_output + ensure + I18n.available_locales = [:en] + I18n.locale = :en + end + end end diff --git a/activejob/test/jobs/translated_hello_job.rb b/activejob/test/jobs/translated_hello_job.rb new file mode 100644 index 0000000000..9657cd3f54 --- /dev/null +++ b/activejob/test/jobs/translated_hello_job.rb @@ -0,0 +1,10 @@ +require_relative '../support/job_buffer' + +class TranslatedHelloJob < ActiveJob::Base + def perform(greeter = "David") + translations = { en: 'Hello', de: 'Guten Tag' } + hello = translations[I18n.locale] + + JobBuffer.add("#{greeter} says #{hello}") + end +end diff --git a/activejob/test/support/integration/dummy_app_template.rb b/activejob/test/support/integration/dummy_app_template.rb index 09a68738ad..4ffdb8cffa 100644 --- a/activejob/test/support/integration/dummy_app_template.rb +++ b/activejob/test/support/integration/dummy_app_template.rb @@ -8,13 +8,17 @@ require "#{File.expand_path("../jobs_manager.rb", __FILE__)}" JobsManager.current_manager.setup CODE +initializer 'i18n.rb', <<-CODE +I18n.available_locales = [:en, :de] +CODE + file 'app/jobs/test_job.rb', <<-CODE class TestJob < ActiveJob::Base queue_as :integration_tests def perform(x) File.open(Rails.root.join("tmp/\#{x}"), "w+") do |f| - f.write x + f.write I18n.locale end end end diff --git a/activejob/test/support/integration/test_case_helpers.rb b/activejob/test/support/integration/test_case_helpers.rb index 7e87ede275..39aee6d407 100644 --- a/activejob/test/support/integration/test_case_helpers.rb +++ b/activejob/test/support/integration/test_case_helpers.rb @@ -45,4 +45,8 @@ module TestCaseHelpers def job_executed Dummy::Application.root.join("tmp/#{@id}").exist? end + + def job_output + File.read Dummy::Application.root.join("tmp/#{@id}") + end end diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md index 22f3c0146a..1715fc327a 100644 --- a/guides/source/active_job_basics.md +++ b/guides/source/active_job_basics.md @@ -280,6 +280,19 @@ UserMailer.welcome(@user).deliver_later ``` +Internationalization +-------------------- + +Each job uses the `I18n.locale` set when the job was created. Useful if you send +emails asynchronously: + +```ruby +I18n.locale = :eo + +UserMailer.welcome(@user).deliver_later # Email will be localized to Esparanto. +``` + + GlobalID -------- |