Module: ActiveRecord::Associations::ThroughAssociation
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
|
Included In:
| |
| Defined in: | activerecord/lib/active_record/associations/through_association.rb |
Overview
Active Record Through Association
Instance Attribute Summary
- #source_reflection readonly
- #foreign_key_present? ⇒ Boolean readonly private
Instance Method Summary
- #build_record(attributes) private
-
#construct_join_attributes(*records, query: false)
private
Construct attributes for
:throughpointing to owner and associate. - #ensure_mutable private
- #ensure_not_nested private
-
#matches_foreign_key?(record) ⇒ Boolean
private
The owner and target aren't directly linked, so their keys can't confirm that a record belongs to this association.
-
#stale_state
private
Note: this does not capture all cases, for example it would be impractical to try to properly support stale-checking for nested associations.
-
#target_scope
private
We merge in these scopes for two reasons:
- #through_association private
- #through_reflection private
- #transaction(&block) private
Instance Attribute Details
#foreign_key_present? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'activerecord/lib/active_record/associations/through_association.rb', line 98
def foreign_key_present? through_reflection.belongs_to? && Array(through_reflection.foreign_key).all? do |foreign_key_column| !owner.read_attr(foreign_key_column).nil? end end
#source_reflection (readonly)
[ GitHub ]# File 'activerecord/lib/active_record/associations/through_association.rb', line 8
delegate :source_reflection, to: :reflection
Instance Method Details
#build_record(attributes) (private)
[ GitHub ]# File 'activerecord/lib/active_record/associations/through_association.rb', line 124
def build_record(attributes) if source_reflection.collection? inverse = source_reflection.inverse_of target = through_association.target if inverse && target && !target.is_a?(Array) route = source_reflection.association_route(origin_class: target.class) attributes.merge!(route.destination_attributes(target)) end end super end
#construct_join_attributes(*records, query: false) (private)
Construct attributes for :through pointing to owner and associate. This is used by the
methods which create and delete records on the association.
We only support indirectly modifying through associations which have a belongs_to source.
This is the "has_many :tags, through: :taggings" situation, where the join model
typically has a belongs_to on both side. In other words, associations which could also
be represented as has_and_belongs_to_many associations.
We do not support creating/deleting records on the association where the source has some other type, because this opens up a whole can of worms, and in basically any situation it is more natural for the user to just create or modify their join records directly as required.
# File 'activerecord/lib/active_record/associations/through_association.rb', line 58
def construct_join_attributes(*records, query: false) ensure_mutable route = reflection.source_association_route origin_key, destination_key = query ? [route.origin_key, route.destination_key] : [route.reference_origin_key, route.reference_destination_key] if destination_key.to_a == reflection.klass.composite_query_constraints_list && ![:source_type] join_attributes = { source_reflection.name => records } else target_values = records.map { |record| destination_key.value_of(record) } join_attributes = { origin_key.name => target_values } end if [:source_type] join_attributes[source_reflection.foreign_type] = [ [:source_type] ] end if records.count == 1 && !(query && destination_key.composite?) join_attributes.transform_values!(&:first) else join_attributes end end
#ensure_mutable (private)
[ GitHub ]# File 'activerecord/lib/active_record/associations/through_association.rb', line 104
def ensure_mutable unless source_reflection.belongs_to? if reflection.has_one? raise HasOneThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection) else raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection) end end end
#ensure_not_nested (private)
[ GitHub ]# File 'activerecord/lib/active_record/associations/through_association.rb', line 114
def ensure_not_nested if reflection.nested? if reflection.has_one? raise HasOneThroughNestedAssociationsAreReadonly.new(owner, reflection) else raise HasManyThroughNestedAssociationsAreReadonly.new(owner, reflection) end end end
#matches_foreign_key?(record) ⇒ Boolean (private)
The owner and target aren't directly linked, so their keys can't confirm that a record belongs to this association.
# File 'activerecord/lib/active_record/associations/through_association.rb', line 94
def matches_foreign_key?(record) false end
#stale_state (private)
Note: this does not capture all cases, for example it would be impractical to try to properly support stale-checking for nested associations.
# File 'activerecord/lib/active_record/associations/through_association.rb', line 84
def stale_state if through_reflection.belongs_to? Array(through_reflection.foreign_key).filter_map do |foreign_key_column| owner.read_attr(foreign_key_column) end.presence end end
#target_scope (private)
We merge in these scopes for two reasons:
1. To get the default_scope conditions for any of the other reflections in the chain
2. To get the type conditions for any STI models in the chain
# File 'activerecord/lib/active_record/associations/through_association.rb', line 35
def target_scope scope = super reflection.chain.drop(1).each do |reflection| relation = reflection.klass.scope_for_association scope.merge!( relation.except(:select, :create_with, :includes, :preload, :eager_load, :joins, :left_outer_joins) ) end scope end
#through_association (private)
[ GitHub ]# File 'activerecord/lib/active_record/associations/through_association.rb', line 27
def through_association @through_association ||= owner.association(through_reflection.name) end
#through_reflection (private)
[ GitHub ]# File 'activerecord/lib/active_record/associations/through_association.rb', line 15
def through_reflection @through_reflection ||= begin refl = reflection.through_reflection while refl.through_reflection? refl = refl.through_reflection end refl end end
#transaction(&block) (private)
[ GitHub ]# File 'activerecord/lib/active_record/associations/through_association.rb', line 11
def transaction(&block) through_reflection.klass.transaction(&block) end