mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
ce6a50c101
During where clause generation we search for scope type for the model. We can do this with Module#!= instead as long as we grab the final scope type after the loop. This is a small, but significant performance improvement. Co-authored-by: John Hawthorn <jhawthorn@github.com>
136 lines
4.1 KiB
Ruby
136 lines
4.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "active_support/core_ext/module/delegation"
|
|
|
|
module ActiveRecord
|
|
module Scoping
|
|
extend ActiveSupport::Concern
|
|
|
|
included do
|
|
include Default
|
|
include Named
|
|
end
|
|
|
|
module ClassMethods # :nodoc:
|
|
# Collects attributes from scopes that should be applied when creating
|
|
# an AR instance for the particular class this is called on.
|
|
def scope_attributes
|
|
all.scope_for_create
|
|
end
|
|
|
|
# Are there attributes associated with this scope?
|
|
def scope_attributes?
|
|
current_scope
|
|
end
|
|
|
|
def current_scope(skip_inherited_scope = false)
|
|
ScopeRegistry.current_scope(self, skip_inherited_scope)
|
|
end
|
|
|
|
def current_scope=(scope)
|
|
ScopeRegistry.set_current_scope(self, scope)
|
|
end
|
|
|
|
def global_current_scope(skip_inherited_scope = false)
|
|
ScopeRegistry.global_current_scope(self, skip_inherited_scope)
|
|
end
|
|
|
|
def global_current_scope=(scope)
|
|
ScopeRegistry.set_global_current_scope(self, scope)
|
|
end
|
|
|
|
def scope_registry
|
|
ScopeRegistry.instance
|
|
end
|
|
end
|
|
|
|
def populate_with_current_scope_attributes # :nodoc:
|
|
return unless self.class.scope_attributes?
|
|
|
|
attributes = self.class.scope_attributes
|
|
_assign_attributes(attributes) if attributes.any?
|
|
end
|
|
|
|
def initialize_internals_callback # :nodoc:
|
|
super
|
|
populate_with_current_scope_attributes
|
|
end
|
|
|
|
# This class stores the +:current_scope+ and +:ignore_default_scope+ values
|
|
# for different classes. The registry is stored as either a thread or fiber
|
|
# local depending on the application configuration.
|
|
#
|
|
# 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_current_scope(Board, some_new_scope)
|
|
#
|
|
# Now when you run:
|
|
#
|
|
# registry.current_scope(Board)
|
|
#
|
|
# You will obtain whatever was defined in +some_new_scope+.
|
|
class ScopeRegistry # :nodoc:
|
|
class << self
|
|
delegate :current_scope, :set_current_scope, :ignore_default_scope, :set_ignore_default_scope,
|
|
:global_current_scope, :set_global_current_scope, to: :instance
|
|
|
|
def instance
|
|
ActiveSupport::IsolatedExecutionState[:active_record_scope_registry] ||= new
|
|
end
|
|
end
|
|
|
|
def initialize
|
|
@current_scope = {}
|
|
@ignore_default_scope = {}
|
|
@global_current_scope = {}
|
|
end
|
|
|
|
def current_scope(model, skip_inherited_scope = false)
|
|
value_for(@current_scope, model, skip_inherited_scope)
|
|
end
|
|
|
|
def set_current_scope(model, value)
|
|
set_value_for(@current_scope, model, value)
|
|
end
|
|
|
|
def ignore_default_scope(model, skip_inherited_scope = false)
|
|
value_for(@ignore_default_scope, model, skip_inherited_scope)
|
|
end
|
|
|
|
def set_ignore_default_scope(model, value)
|
|
set_value_for(@ignore_default_scope, model, value)
|
|
end
|
|
|
|
def global_current_scope(model, skip_inherited_scope = false)
|
|
value_for(@global_current_scope, model, skip_inherited_scope)
|
|
end
|
|
|
|
def set_global_current_scope(model, value)
|
|
set_value_for(@global_current_scope, model, value)
|
|
end
|
|
|
|
private
|
|
# Obtains the value for a given +scope_type+ and +model+.
|
|
def value_for(scope_type, model, skip_inherited_scope = false)
|
|
return scope_type[model.name] if skip_inherited_scope
|
|
klass = model
|
|
base = model.base_class
|
|
while klass != base
|
|
value = scope_type[klass.name]
|
|
return value if value
|
|
klass = klass.superclass
|
|
end
|
|
scope_type[klass.name]
|
|
end
|
|
|
|
# Sets the +value+ for a given +scope_type+ and +model+.
|
|
def set_value_for(scope_type, model, value)
|
|
scope_type[model.name] = value
|
|
end
|
|
end
|
|
end
|
|
end
|