aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/scoping.rb
diff options
context:
space:
mode:
authorwangjohn <wangjohn@mit.edu>2013-04-08 02:56:21 -0400
committerwangjohn <wangjohn@mit.edu>2013-04-08 13:21:13 -0400
commit5b945f2685bf9ec77ddf0d79d09f0000d827cd22 (patch)
tree7f843c6e3005202756bd2eea01c5f36f84623552 /activerecord/lib/active_record/scoping.rb
parent63f7356b3ae5d5f9a0710e52f6392bdcd269d903 (diff)
downloadrails-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/active_record/scoping.rb')
-rw-r--r--activerecord/lib/active_record/scoping.rb55
1 files changed, 53 insertions, 2 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