1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/activerecord/lib/active_record/scoping.rb
Xavier Noria e5ef3abdd2 hides the per thread registry instance, and caches singleton methods
Existing code was delegating to the instance with delegate
macro calls, or invoking the instance method to reach
the object and call its instance methods.

But the point is to have a clean class-level interface where
the thread local instance is hidden in the implementation.

References #11c6973.
References #10198.
2013-04-13 17:09:13 +02:00

82 lines
2.6 KiB
Ruby

require 'active_support/per_thread_registry'
module ActiveRecord
module Scoping
extend ActiveSupport::Concern
included do
include Default
include Named
end
module ClassMethods
def current_scope #:nodoc:
ScopeRegistry.value_for(:current_scope, base_class.to_s)
end
def current_scope=(scope) #:nodoc:
ScopeRegistry.set_value_for(:current_scope, base_class.to_s, scope)
end
end
def populate_with_current_scope_attributes
return unless self.class.scope_attributes?
self.class.scope_attributes.each do |att,value|
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
# 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+. The +value_for+
# and +set_value_for+ methods are delegated to the current +ScopeRegistry+
# object, so the above example code can also be called as:
#
# ActiveRecord::Scoping::ScopeRegistry.set_value_for(:current_scope,
# "Board", some_new_scope)
class ScopeRegistry # :nodoc:
extend ActiveSupport::PerThreadRegistry
VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope]
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