diff options
author | wangjohn <wangjohn@mit.edu> | 2013-04-08 02:56:21 -0400 |
---|---|---|
committer | wangjohn <wangjohn@mit.edu> | 2013-04-08 13:21:13 -0400 |
commit | 5b945f2685bf9ec77ddf0d79d09f0000d827cd22 (patch) | |
tree | 7f843c6e3005202756bd2eea01c5f36f84623552 /activerecord/lib | |
parent | 63f7356b3ae5d5f9a0710e52f6392bdcd269d903 (diff) | |
download | rails-5b945f2685bf9ec77ddf0d79d09f0000d827cd22.tar.gz rails-5b945f2685bf9ec77ddf0d79d09f0000d827cd22.tar.bz2 rails-5b945f2685bf9ec77ddf0d79d09f0000d827cd22.zip |
Grouping thread locals in the ActiveRecord scopes so that the
current_scope and ignore_default_scope locals are brought together under
a registry object.
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/scoping.rb | 55 | ||||
-rw-r--r-- | activerecord/lib/active_record/scoping/default.rb | 4 |
2 files changed, 55 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb index 886182f534..b631730ab3 100644 --- a/activerecord/lib/active_record/scoping.rb +++ b/activerecord/lib/active_record/scoping.rb @@ -9,11 +9,11 @@ module ActiveRecord module ClassMethods def current_scope #:nodoc: - Thread.current["#{base_class}_current_scope"] + ScopeRegistry.current.value_for(:current_scope, base_class.to_s) end def current_scope=(scope) #:nodoc: - Thread.current["#{base_class}_current_scope"] = scope + ScopeRegistry.current.set_value_for(:current_scope, base_class.to_s, scope) end end @@ -24,5 +24,56 @@ module ActiveRecord send("#{att}=", value) if respond_to?("#{att}=") end end + + # This class stores the +:current_scope+ and +:ignore_default_scope+ values + # for different classes. The registry is stored as a thread local, which is + # accessed through +ScopeRegistry.current+. + # + # This class allows you to store and get the scope values on different + # classes and different types of scopes. For example, if you are attempting + # to get the current_scope for the +Board+ model, then you would use the + # following code: + # + # registry = ActiveRecord::Scoping::ScopeRegistry.current + # registry.set_value_for(:current_scope, "Board", some_new_scope) + # + # Now when you run: + # + # registry.value_for(:current_scope, "Board") + # + # You will obtain whatever was defined in +some_new_scope+. + class ScopeRegistry # :nodoc: + def self.current + Thread.current["scope_registry"] ||= new + end + + VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope] + + attr_accessor :registry + + def initialize + @registry = Hash.new { |hash, key| hash[key] = {} } + end + + # Obtains the value for a given +scope_name+ and +variable_name+. + def value_for(scope_type, variable_name) + raise_invalid_scope_type!(scope_type) + @registry[scope_type][variable_name] + end + + # Sets the +value+ for a given +scope_type+ and +variable_name+. + def set_value_for(scope_type, variable_name, value) + raise_invalid_scope_type!(scope_type) + @registry[scope_type][variable_name] = value + end + + private + + def raise_invalid_scope_type!(scope_type) + if !VALID_SCOPE_TYPES.include?(scope_type) + raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES" + end + end + end end end diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb index 8a90528ce8..daee771669 100644 --- a/activerecord/lib/active_record/scoping/default.rb +++ b/activerecord/lib/active_record/scoping/default.rb @@ -120,11 +120,11 @@ module ActiveRecord end def ignore_default_scope? # :nodoc: - Thread.current["#{self}_ignore_default_scope"] + ScopeRegistry.current.value_for(:ignore_default_scope, self) end def ignore_default_scope=(ignore) # :nodoc: - Thread.current["#{self}_ignore_default_scope"] = ignore + ScopeRegistry.current.set_value_for(:ignore_default_scope, self, ignore) end # The ignore_default_scope flag is used to prevent an infinite recursion |