diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 0f348c3ef4..459c5fccc1 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -117,6 +117,10 @@ module ActiveSupport def self.utc_to_local_returns_utc_offset_times=(value) DateAndTime::Compatibility.utc_to_local_returns_utc_offset_times = value end + + def self.current_attributes_use_thread_variables=(value) + CurrentAttributes._use_thread_variables = value + end end autoload :I18n, "active_support/i18n" diff --git a/activesupport/lib/active_support/current_attributes.rb b/activesupport/lib/active_support/current_attributes.rb index cc1a7e92b2..64f3d51114 100644 --- a/activesupport/lib/active_support/current_attributes.rb +++ b/activesupport/lib/active_support/current_attributes.rb @@ -143,13 +143,23 @@ module ActiveSupport current_instances.clear end + def _use_thread_variables=(value) # :nodoc: + @@use_thread_variables = value + end + @@use_thread_variables = false + private def generated_attribute_methods @generated_attribute_methods ||= Module.new.tap { |mod| include mod } end def current_instances - Thread.current[:current_attributes_instances] ||= {} + if @@use_thread_variables + Thread.current.thread_variable_get(:current_attributes_instances) || + Thread.current.thread_variable_set(:current_attributes_instances, {}) + else + Thread.current[:current_attributes_instances] ||= {} + end end def current_instances_key diff --git a/activesupport/test/current_attributes_test.rb b/activesupport/test/current_attributes_test.rb index 1544557f49..0196331d13 100644 --- a/activesupport/test/current_attributes_test.rb +++ b/activesupport/test/current_attributes_test.rb @@ -174,4 +174,23 @@ class CurrentAttributesTest < ActiveSupport::TestCase test "respond_to? for methods that have not been called" do assert_equal true, Current.respond_to?("respond_to_test") end + + test "CurrentAttributes use fiber-local variables" do + Session.current = 42 + enumerator = Enumerator.new do |yielder| + yielder.yield Session.current + end + assert_nil enumerator.next + end + + test "CurrentAttributes can use thread-local variables" do + ActiveSupport::CurrentAttributes._use_thread_variables = true + Session.current = 42 + enumerator = Enumerator.new do |yielder| + yielder.yield Session.current + end + assert_equal 42, enumerator.next + ensure + ActiveSupport::CurrentAttributes._use_thread_variables = false + end end