123456789_123456789_123456789_123456789_123456789_

Class: ActiveRecord::AssociationLink

Do not use. This class is for internal use only.
Relationships & Source Files
Namespace Children
Classes:
Inherits: Object
Defined in: activerecord/lib/active_record/association_route.rb

Overview

An association's writable foreign-key reference and query-only constraints from the perspective of the record that holds the foreign key.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(reference: nil, reference_key: reference&.reference_key, constraints: Key::Mapping.empty, fixed_values: EMPTY_FIXED_VALUES, reference_class: nil, target_class: nil) ⇒ AssociationLink

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 30

def initialize(reference: nil, reference_key: reference&.reference_key, constraints: Key::Mapping.empty, fixed_values: EMPTY_FIXED_VALUES, reference_class: nil, target_class: nil)
  @reference = reference
  @reference_key = reference_key
  @constraints = constraints
  @fixed_values = fixed_values.freeze
  @match = (constraints + reference).normalize if reference

  @_reference_key = resolve_aliases(reference_key, reference_class)
  @_target_key = resolve_aliases(reference&.target_key, target_class)
  @_match_reference_key = resolve_aliases(@match&.reference_key, reference_class)
  @_match_target_key = resolve_aliases(@match&.target_key, target_class)
  @_fixed_values = resolve_fixed_values(@fixed_values, reference_class)

  @hash = [self.class, reference, reference_key, constraints, @fixed_values,
    @_reference_key, @_target_key, @_match_reference_key, @_match_target_key].hash
  freeze
end

Class Method Details

.for(reference_class: nil, **options)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 13

def self.for(reference_class: nil, **options)
  link = new(reference_class: reference_class, **options)
  if link.send(:writes_mapped_id?, reference_class)
    DeprecatedIdWriter.new(reference_class: reference_class, **options)
  else
    link
  end
end

Instance Attribute Details

#_fixed_values (readonly)

Physical (alias-resolved) counterparts of the above.

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 28

attr_reader :_reference_key, :_target_key, :_match_reference_key, :_match_target_key, :_fixed_values

#_match_reference_key (readonly)

Physical (alias-resolved) counterparts of the above.

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 28

attr_reader :_reference_key, :_target_key, :_match_reference_key, :_match_target_key, :_fixed_values

#_match_target_key (readonly)

Physical (alias-resolved) counterparts of the above.

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 28

attr_reader :_reference_key, :_target_key, :_match_reference_key, :_match_target_key, :_fixed_values

#_reference_key (readonly)

Physical (alias-resolved) counterparts of the above.

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 28

attr_reader :_reference_key, :_target_key, :_match_reference_key, :_match_target_key, :_fixed_values

#_target_key (readonly)

Physical (alias-resolved) counterparts of the above.

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 28

attr_reader :_reference_key, :_target_key, :_match_reference_key, :_match_target_key, :_fixed_values

#constraints (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 22

attr_reader :reference, :reference_key, :constraints, :match

#fixed_values (readonly)

Attributes written alongside the foreign key, such as a polymorphic type.

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 25

attr_reader :fixed_values

#hash (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 61

attr_reader :hash

#match (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 22

attr_reader :reference, :reference_key, :constraints, :match

#reference (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 22

attr_reader :reference, :reference_key, :constraints, :match

#reference_key (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 22

attr_reader :reference, :reference_key, :constraints, :match

Instance Method Details

#==(other) Also known as: #eql?

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 48

def ==(other)
  other.instance_of?(self.class) &&
    reference == other.reference &&
    reference_key == other.reference_key &&
    constraints == other.constraints &&
    fixed_values == other.fixed_values &&
    _reference_key == other._reference_key &&
    _target_key == other._target_key &&
    _match_reference_key == other._match_reference_key &&
    _match_target_key == other._match_target_key
end

#clear_reference(reference_record, preserve: nil, fixed_values: true, force: true)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 94

def clear_reference(reference_record, preserve: nil, fixed_values: true, force: true)
  _reference_key.each do |column|
    next if preserve&.include?(column)
    reference_record._write_attribute(column, nil)
  end
  return unless fixed_values

  _fixed_values.each_key do |column|
    next if !force && reference_record._read_attr(column).nil?
    reference_record._write_attribute(column, nil)
  end
end

#each_reference_key_value(target_record) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 132

def each_reference_key_value(target_record)
  return enum_for(__method__, target_record) unless block_given?

  target_columns = reference.target_key.columns if target_record

  reference_key.each_with_index do |column, index|
    yield column, target_record&.read_attr(target_columns[index])
  end
end

#each_reference_value(target_record) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 125

def each_reference_value(target_record, &)
  return enum_for(__method__, target_record) unless block_given?

  each_reference_key_value(target_record, &)
  fixed_values.each(&)
end

#eql?(other)

Alias for #==.

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 59

alias_method :eql?, :==

#reference_needs_update?(reference_record, target_record) ⇒ Boolean

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 67

def reference_needs_update?(reference_record, target_record)
  if _reference_key.all? { |column| reference_record._has_attribute?(column) }
    target_columns = _target_key.columns if target_record
    _reference_key.each_with_index do |column, index|
      return true if reference_record._read_attr(column) != target_record&._read_attr(target_columns[index])
    end
  end

  _fixed_values.any? do |column, value|
    reference_record._has_attribute?(column) && reference_record._read_attr(column) != value
  end
end

#reference_values(target_record)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 63

def reference_values(target_record)
  each_reference_value(target_record).to_h
end

#resolve_aliases(key, owner) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 116

def resolve_aliases(key, owner)
  owner ? key&.resolve_aliases(owner) : key
end

#resolve_fixed_values(fixed_values, owner) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 120

def resolve_fixed_values(fixed_values, owner)
  return fixed_values if owner.nil? || fixed_values.none? { |column, _| owner.resolve_alias(column) != column }
  fixed_values.to_h { |column, value| [-owner.resolve_alias(column), value] }.freeze
end

#write_reference(reference_record, target_record, force: true)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 80

def write_reference(reference_record, target_record, force: true)
  target_columns = _target_key.columns if target_record
  _reference_key.each_with_index do |column, index|
    value = target_record&._read_attr(target_columns[index])
    next if !force && reference_record._read_attr(column) == value
    reference_record._write_attribute(column, value)
  end

  _fixed_values.each do |column, value|
    next if !force && reference_record._read_attr(column) == value
    reference_record._write_attribute(column, value)
  end unless _fixed_values.empty?
end

#writes_mapped_id?(reference_class) ⇒ Boolean (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/association_route.rb', line 108

def writes_mapped_id?(reference_class)
  return false unless reference_class

  primary_key = reference_class.primary_key
  primary_key && primary_key != "id" && !reference_class.composite_primary_key? &&
    (_reference_key.include?("id") || _fixed_values.key?("id"))
end