class ActiveRecord::Reflection::AssociationReflection

:nodoc:
Active Record class.
Holds all the metadata about an association as it was specified in the

def active_record_primary_key

def active_record_primary_key
  custom_primary_key = options[:primary_key]
  @active_record_primary_key ||= if custom_primary_key
    if custom_primary_key.is_a?(Array)
      custom_primary_key.map { |pk| pk.to_s.freeze }.freeze
    else
      custom_primary_key.to_s.freeze
    end
  elsif active_record.has_query_constraints? || options[:query_constraints]
    active_record.query_constraints_list
  elsif active_record.composite_primary_key?
    # If active_record has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
    primary_key = primary_key(active_record)
    primary_key.include?("id") ? "id" : primary_key.freeze
  else
    primary_key(active_record).freeze
  end
end

def add_as_polymorphic_through(reflection, seed)

def add_as_polymorphic_through(reflection, seed)
  seed + [PolymorphicReflection.new(self, reflection)]
end

def add_as_source(seed)

def add_as_source(seed)
  seed
end

def add_as_through(seed)

def add_as_through(seed)
  seed + [self]
end

def association_class; raise NotImplementedError; end

def association_class; raise NotImplementedError; end

def association_foreign_key

def association_foreign_key
  @association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
end

def association_primary_key(klass = nil)

def association_primary_key(klass = nil)
  primary_key(klass || self.klass)
end

def association_scope_cache(klass, owner, &block)

def association_scope_cache(klass, owner, &block)
  key = self
  if polymorphic?
    key = [key, owner._read_attribute(@foreign_type)]
  end
  klass.cached_find_by_statement(key, &block)
end

def automatic_inverse_of

returns either +nil+ or the inverse association name that it finds.
def automatic_inverse_of
  if can_find_inverse_of_automatically?(self)
    inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
    begin
      reflection = klass._reflect_on_association(inverse_name)
    rescue NameError => error
      raise unless error.name.to_s == class_name
      # Give up: we couldn't compute the klass type so we won't be able
      # to find any associations either.
      reflection = false
    end
    if valid_inverse_reflection?(reflection)
      inverse_name
    end
  end
end

def belongs_to?; false; end

Returns +true+ if +self+ is a +belongs_to+ reflection.
def belongs_to?; false; end

def can_find_inverse_of_automatically?(reflection, inverse_reflection = false)

which prevent us from correctly guessing the inverse association.
Third, we must not have options such as :foreign_key
have has_many, has_one, belongs_to associations.
inverse_of option cannot be set to false. Second, we must
us from being able to guess the inverse automatically. First, the
Checks to see if the reflection doesn't have any options that prevent
def can_find_inverse_of_automatically?(reflection, inverse_reflection = false)
  reflection.options[:inverse_of] != false &&
    !reflection.options[:through] &&
    !reflection.options[:foreign_key] &&
    scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
end

def check_eager_loadable!

def check_eager_loadable!
  return unless scope
  unless scope.arity == 0
    raise ArgumentError, <<-MSG.squish
      The association scope '#{name}' is instance dependent (the scope
      block takes an argument). Eager loading instance dependent scopes
      is not supported.
    MSG
  end
end

def check_validity!

def check_validity!
  check_validity_of_inverse!
  if !polymorphic? && (klass.composite_primary_key? || active_record.composite_primary_key?)
    if (has_one? || collection?) && Array(active_record_primary_key).length != Array(foreign_key).length
      raise CompositePrimaryKeyMismatchError.new(self)
    elsif belongs_to? && Array(association_primary_key).length != Array(foreign_key).length
      raise CompositePrimaryKeyMismatchError.new(self)
    end
  end
end

def clear_association_scope_cache # :nodoc:

:nodoc:
SQL queries on associations.
This is for clearing cache on the reflection. Useful for tests that need to compare
def clear_association_scope_cache # :nodoc:
  klass.initialize_find_by_cache
end

def collect_join_chain

ThroughReflection.
A chain of reflections from this one back to the owner. For more see the explanation in
def collect_join_chain
  [self]
end

def collection?

+has_and_belongs_to_many+, +false+ otherwise.
association. Returns +true+ if the +macro+ is either +has_many+ or
Returns whether or not this association reflection is for a collection
def collection?
  false
end

def compute_class(name)

:nodoc:
Active Record class.
Holds all the metadata about an association as it was specified in the
def compute_class(name)
  if polymorphic?
    raise ArgumentError, "Polymorphic associations do not support computing the class."
  end
  begin
    klass = active_record.send(:compute_type, name)
  rescue NameError => error
    if error.name.match?(/(?:\A|::)#{name}\z/)
      message = "Missing model class #{name} for the #{active_record}##{self.name} association."
      message += " You can specify a different model class with the :class_name option." unless options[:class_name]
      raise NameError.new(message, name)
    else
      raise
    end
  end
  unless klass < ActiveRecord::Base
    raise ArgumentError, "The #{name} model class for the #{active_record}##{self.name} association is not an ActiveRecord::Base subclass."
  end
  klass
end

def derive_class_name

def derive_class_name
  class_name = name.to_s
  class_name = class_name.singularize if collection?
  class_name.camelize
end

def derive_fk_query_constraints(foreign_key)

def derive_fk_query_constraints(foreign_key)
  primary_query_constraints = active_record.query_constraints_list
  owner_pk = active_record.primary_key
  if primary_query_constraints.size != 2
    raise ArgumentError, <<~MSG.squish
      The query constraints list on the `#{active_record}` model has more than 2
      attributes. Active Record is unable to derive the query constraints
      for the association. You need to explicitly define the query constraints
      for this association.
    MSG
  end
  if !primary_query_constraints.include?(owner_pk)
    raise ArgumentError, <<~MSG.squish
      The query constraints on the `#{active_record}` model does not include the primary
      key so Active Record is unable to derive the foreign key constraints for
      the association. You need to explicitly define the query constraints for this
      association.
    MSG
  end
  first_key, last_key = primary_query_constraints
  if first_key == owner_pk
    [foreign_key, last_key.to_s]
  elsif last_key == owner_pk
    [first_key.to_s, foreign_key]
  else
    raise ArgumentError, <<~MSG.squish
      Active Record couldn't correctly interpret the query constraints
      for the `#{active_record}` model. The query constraints on `#{active_record}` are
      `#{primary_query_constraints}` and the foreign key is `#{foreign_key}`.
      You need to explicitly set the query constraints for this association.
    MSG
  end
end

def derive_foreign_key(infer_from_inverse_of: true)

def derive_foreign_key(infer_from_inverse_of: true)
  if belongs_to?
    "#{name}_id"
  elsif options[:as]
    "#{options[:as]}_id"
  elsif options[:inverse_of] && infer_from_inverse_of
    inverse_of.foreign_key(infer_from_inverse_of: false)
  else
    active_record.model_name.to_s.foreign_key
  end
end

def derive_join_table

def derive_join_table
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
end

def extensions

def extensions
  Array(options[:extend])
end

def foreign_key(infer_from_inverse_of: true)

def foreign_key(infer_from_inverse_of: true)
  @foreign_key ||= if options[:query_constraints]
    options[:query_constraints].map { |fk| fk.to_s.freeze }.freeze
  elsif options[:foreign_key]
    options[:foreign_key].to_s
  else
    derived_fk = derive_foreign_key(infer_from_inverse_of: infer_from_inverse_of)
    if active_record.has_query_constraints?
      derived_fk = derive_fk_query_constraints(derived_fk)
    end
    derived_fk
  end
end

def has_inverse?

def has_inverse?
  inverse_name
end

def has_one?; false; end

Returns +true+ if +self+ is a +has_one+ reflection.
def has_one?; false; end

def has_scope?

def has_scope?
  scope
end

def initialize(name, scope, options, active_record)

def initialize(name, scope, options, active_record)
  super
  @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
  @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
  @join_table = nil
  @foreign_key = nil
  @association_foreign_key = nil
  @association_primary_key = nil
  ensure_option_not_given_as_class!(:class_name)
end

def inverse_name

+nil+.
If it cannot find a suitable inverse association name, it returns
Attempts to find the inverse association name automatically.
def inverse_name
  unless defined?(@inverse_name)
    @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of }
  end
  @inverse_name
end

def join_foreign_key

def join_foreign_key
  active_record_primary_key
end

def join_id_for(owner) # :nodoc:

:nodoc:
def join_id_for(owner) # :nodoc:
  Array(join_foreign_key).map { |key| owner._read_attribute(key) }
end

def join_primary_key(klass = nil)

def join_primary_key(klass = nil)
  foreign_key
end

def join_primary_type

def join_primary_type
  type
end

def join_table

def join_table
  @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
end

def macro; raise NotImplementedError; end

has_many :clients returns :has_many

Returns the macro type.
def macro; raise NotImplementedError; end

def nested?

def nested?
  false
end

def polymorphic?

def polymorphic?
  options[:polymorphic]
end

def polymorphic_inverse_of(associated_class)

def polymorphic_inverse_of(associated_class)
  if has_inverse?
    if inverse_relationship = associated_class._reflect_on_association(options[:inverse_of])
      inverse_relationship
    else
      raise InverseOfAssociationNotFoundError.new(self, associated_class)
    end
  end
end

def polymorphic_name

def polymorphic_name
  active_record.polymorphic_name
end

def scope_allows_automatic_inverse_of?(reflection, inverse_reflection)

+true+ (the default for new applications).
config.active_record.automatic_scope_inversing is set to
automatic inverse_of as long as
we would inverse from. Scopes on the reflection itself allow for
inverse_of, since the scope could exclude the owner record
Scopes on the potential inverse reflection prevent automatic
def scope_allows_automatic_inverse_of?(reflection, inverse_reflection)
  if inverse_reflection
    !reflection.scope
  else
    !reflection.scope || reflection.klass.automatic_scope_inversing
  end
end

def source_reflection

def source_reflection
  self
end

def through_reflection

def through_reflection
  nil
end

def valid_inverse_reflection?(reflection)

with the current reflection's klass name.
make sure that the reflection's active_record name matches up
+automatic_inverse_of+ method is a valid reflection. We must
Checks if the inverse reflection that is returned from the
def valid_inverse_reflection?(reflection)
  reflection &&
    reflection != self &&
    foreign_key == reflection.foreign_key &&
    klass <= reflection.active_record &&
    can_find_inverse_of_automatically?(reflection, true)
end

def validate?

* the association is a +has_many+ association
* you use autosave; autosave: true
* you explicitly enable validation; validate: true

validate: false, validation will take place when:
Unless you explicitly disable validation with

the parent's validation.
Returns whether or not the association should be validated as part of
def validate?
  !options[:validate].nil? ? options[:validate] : (options[:autosave] == true || collection?)
end