class ActiveRecord::Reflection::AbstractReflection
:nodoc:
RuntimeReflection
PolymorphicReflection
ThroughReflection
HasAndBelongsToManyReflection
BelongsToReflection
HasOneReflection
HasManyReflection
AssociationReflection
AggregateReflection
MacroReflection
AbstractReflection
Holds all the methods that are shared between MacroReflection and ThroughReflection.
def actual_source_reflection # FIXME: this is a horrible name
def actual_source_reflection # FIXME: this is a horrible name self end
def alias_candidate(name)
def alias_candidate(name) "#{plural_name}_#{name}" end
def build_association(attributes, &block)
Returns a new, unsaved instance of the associated class. +attributes+ will
def build_association(attributes, &block) klass.new(attributes, &block) end
def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass) Relation.create( klass, table: table, predicate_builder: predicate_builder ) end
def chain
def chain collect_join_chain end
def check_validity_of_inverse!
def check_validity_of_inverse! unless polymorphic? if has_inverse? && inverse_of.nil? raise InverseOfAssociationNotFoundError.new(self) end if has_inverse? && inverse_of == self raise InverseOfAssociationRecursiveError.new(self) end end end
def class_name
composed_of :balance, class_name: 'Money' returns 'Money'
Returns the class name for the macro.
def class_name @class_name ||= -(options[:class_name] || derive_class_name).to_s end
def constraints
def constraints chain.flat_map(&:scopes) end
def counter_cache_column
def counter_cache_column @counter_cache_column ||= if belongs_to? if options[:counter_cache] == true -"#{active_record.name.demodulize.underscore.pluralize}_count" elsif options[:counter_cache] -options[:counter_cache].to_s end else -(options[:counter_cache]&.to_s || "#{name}_count") end end
def counter_must_be_updated_by_has_many?
def counter_must_be_updated_by_has_many? !inverse_updates_counter_in_memory? && has_cached_counter? end
def ensure_option_not_given_as_class!(option_name)
def ensure_option_not_given_as_class!(option_name) if options[option_name] && options[option_name].class == Class raise ArgumentError, "A class was passed to `:#{option_name}` but we are expecting a string." end end
def has_cached_counter?
The counter_cache option must be given on either the owner or inverse
Returns whether a counter cache should be used for this association.
def has_cached_counter? options[:counter_cache] || inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] && active_record.has_attribute?(counter_cache_column) end
def inverse_of
def inverse_of return unless inverse_name @inverse_of ||= klass._reflect_on_association inverse_name end
def inverse_updates_counter_in_memory?
def inverse_updates_counter_in_memory? inverse_of && inverse_which_updates_counter_cache == inverse_of end
def inverse_which_updates_counter_cache
it will be decremented twice.
* In which case, we must make sure to *not* update the counter cache, or else
counter cache.
:counter_cache options which points back at our owner. So they update the
* Hence the callbacks run, and they find a belongs_to on the record with a
* An associated record is deleted via record.destroy
We need to avoid the following situation:
def inverse_which_updates_counter_cache return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache) @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse| inverse.counter_cache_column == counter_cache_column end end
def join_scope(table, foreign_table, foreign_klass)
def join_scope(table, foreign_table, foreign_klass) predicate_builder = predicate_builder(table) scope_chain_items = join_scopes(table, predicate_builder) klass_scope = klass_join_scope(table, predicate_builder) if type klass_scope.where!(type => foreign_klass.polymorphic_name) end scope_chain_items.inject(klass_scope, &:merge!) primary_key = join_primary_key foreign_key = join_foreign_key klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key])) if klass.finder_needs_type_condition? klass_scope.where!(klass.send(:type_condition, table)) end klass_scope end
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc: if scope [scope_for(build_scope(table, predicate_builder, klass), record)] else [] end end
def klass_join_scope(table, predicate_builder) # :nodoc:
def klass_join_scope(table, predicate_builder) # :nodoc: relation = build_scope(table, predicate_builder) klass.scope_for_association(relation) end
def predicate_builder(table)
def predicate_builder(table) PredicateBuilder.new(TableMetadata.new(klass, table)) end
def primary_key(klass)
def primary_key(klass) klass.primary_key || raise(UnknownPrimaryKey.new(klass)) end
def scopes
Returns a list of scopes that should be applied for this Reflection
def scopes scope ? [scope] : [] end
def strict_loading?
def strict_loading? options[:strict_loading] end
def strict_loading_violation_message(owner)
def strict_loading_violation_message(owner) message = +"`#{owner}` is marked for strict_loading." message << " The #{polymorphic? ? "polymorphic association" : "#{klass} association"}" message << " named `:#{name}` cannot be lazily loaded." end
def table_name
def table_name klass.table_name end
def through_reflection?
RuntimeReflection
PolymorphicReflection
ThroughReflection
HasAndBelongsToManyReflection
BelongsToReflection
HasOneReflection
HasManyReflection
AssociationReflection
AggregateReflection
MacroReflection
AbstractReflection
Holds all the methods that are shared between MacroReflection and ThroughReflection.
def through_reflection? false end