123456789_123456789_123456789_123456789_123456789_

Class: ActiveRecord::Associations::AssociationScope

Do not use. This class is for internal use only.
Relationships & Source Files
Namespace Children
Classes:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Inherits: Object
Defined in: activerecord/lib/active_record/associations/association_scope.rb

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(value_transformation) ⇒ AssociationScope

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 15

def initialize(value_transformation)
  @value_transformation = value_transformation
end

Class Method Details

.create(&block)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 10

def self.create(&block)
  block ||= lambda { |val| val }
  new(block)
end

.get_bind_values(owner, chain)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 34

def self.get_bind_values(owner, chain)
  binds = []
  last_reflection = chain.last

  binds.push(*last_reflection.join_id_for(owner))
  if last_reflection.type
    binds << owner.class.polymorphic_name
  end

  chain.each_cons(2).each do |reflection, next_reflection|
    if reflection.type
      binds << next_reflection.klass.polymorphic_name
    end
  end
  binds
end

.scope(association)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 6

def self.scope(association)
  INSTANCE.scope(association)
end

Instance Attribute Details

#value_transformation (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 52

attr_reader :value_transformation

Instance Method Details

#add_constraints(scope, owner, chain)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 124

def add_constraints(scope, owner, chain)
  scope = last_chain_scope(scope, chain.last, owner)

  chain.each_cons(2) do |reflection, next_reflection|
    scope = next_chain_scope(scope, reflection, next_reflection)
  end

  chain_head = chain.first
  chain.reverse_each do |reflection|
    reflection.constraints.each do |scope_chain_item|
      item = eval_scope(reflection, scope_chain_item, owner)

      if scope_chain_item == chain_head.scope
        scope.merge! item.except(:where, :includes, :unscope, :order)
      elsif !item.references_values.empty?
        scope.merge! item.only(:joins, :left_outer_joins)

        associations = item.eager_load_values | item.includes_values

        unless associations.empty?
          scope.joins! item.construct_join_dependency(associations, Arel::Nodes::OuterJoin)
        end
      end

      reflection.all_includes do
        scope.includes_values |= item.includes_values
      end

      scope.unscope!(*item.unscope_values)
      scope.where_clause += item.where_clause
      scope.order_values = item.order_values | scope.order_values
    end
  end

  scope
end

#apply_scope(scope, table, key, value)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 161

def apply_scope(scope, table, key, value)
  if scope.table == table
    scope.where!(key => value)
  else
    scope.where!(table.name => { key => value })
  end
end

#eval_scope(reflection, scope, owner)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 169

def eval_scope(reflection, scope, owner)
  relation = reflection.build_scope(reflection.aliased_table)
  relation.instance_exec(owner, &scope) || relation
end

#get_chain(reflection, association, tracker)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 112

def get_chain(reflection, association, tracker)
  name = reflection.name
  chain = [Reflection::RuntimeReflection.new(reflection, association)]
  reflection.chain.drop(1).each do |refl|
    aliased_table = tracker.aliased_table_for(refl.klass.arel_table) do
      refl.alias_candidate(name)
    end
    chain << ReflectionProxy.new(refl, aliased_table)
  end
  chain
end

#join(table, constraint) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 54

def join(table, constraint)
  Arel::Nodes::LeadingJoin.new(table, Arel::Nodes::On.new(constraint))
end

#last_chain_scope(scope, reflection, owner) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 58

def last_chain_scope(scope, reflection, owner)
  primary_key = Array(reflection.join_primary_key)
  foreign_key = Array(reflection.join_foreign_key)

  table = reflection.aliased_table
  primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
  primary_key_foreign_key_pairs.each do |join_key, foreign_key|
    value = transform_value(owner._read_attribute(foreign_key))
    scope = apply_scope(scope, table, join_key, value)
  end

  if reflection.type
    polymorphic_type = transform_value(owner.class.polymorphic_name)
    scope = apply_scope(scope, table, reflection.type, polymorphic_type)
  end

  scope
end

#next_chain_scope(scope, reflection, next_reflection) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 81

def next_chain_scope(scope, reflection, next_reflection)
  primary_key = Array(reflection.join_primary_key)
  foreign_key = Array(reflection.join_foreign_key)

  table = reflection.aliased_table
  foreign_table = next_reflection.aliased_table

  primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
  constraints = primary_key_foreign_key_pairs.map do |join_primary_key, foreign_key|
    table[join_primary_key].eq(foreign_table[foreign_key])
  end.inject(&:and)

  if reflection.type
    value = transform_value(next_reflection.klass.polymorphic_name)
    scope = apply_scope(scope, table, reflection.type, value)
  end

  scope.joins!(join(foreign_table, constraints))
end

#scope(association)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 21

def scope(association)
  klass = association.klass
  reflection = association.reflection
  scope = klass.unscoped
  owner = association.owner
  chain = get_chain(reflection, association, scope.alias_tracker)

  scope.extending! reflection.extensions
  scope = add_constraints(scope, owner, chain)
  scope.limit!(1) unless reflection.collection?
  scope
end

#transform_value(value) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/associations/association_scope.rb', line 77

def transform_value(value)
  value_transformation.call(value)
end