Class: ActiveRecord::Associations::JoinDependency::JoinAssociation

Inherits:
JoinPart
  • Object
show all
Includes:
ActiveRecord::Associations::JoinHelper
Defined in:
activerecord/lib/active_record/associations/join_dependency/join_association.rb

Overview

:nodoc:

Instance Attribute Summary collapse

Attributes inherited from JoinPart

#active_record

Instance Method Summary collapse

Methods inherited from JoinPart

#aliased_primary_key, #aliased_table, #column_names_with_alias, #extract_record, #instantiate, #record_id

Constructor Details

#initialize(reflection, join_dependency, parent = nil) ⇒ JoinAssociation

Returns a new instance of JoinAssociation


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 33

def initialize(reflection, join_dependency, parent = nil)
  reflection.check_validity!

  if reflection.options[:polymorphic]
    raise EagerLoadPolymorphicError.new(reflection)
  end

  super(reflection.klass)

  @reflection      = reflection
  @join_dependency = join_dependency
  @parent          = parent
  @join_type       = Arel::InnerJoin
  @aliased_prefix  = "t#{ join_dependency.join_parts.size }"
  @tables          = construct_tables.reverse
end

Instance Attribute Details

#aliased_prefixObject (readonly)

These implement abstract methods from the superclass


23
24
25
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 23

def aliased_prefix
  @aliased_prefix
end

#join_dependencyObject (readonly)

The JoinDependency object which this JoinAssociation exists within. This is mainly relevant for generating aliases which do not conflict with other joins which are part of the query.


13
14
15
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 13

def join_dependency
  @join_dependency
end

#join_typeObject

What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin


20
21
22
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 20

def join_type
  @join_type
end

#parentObject (readonly)

A JoinBase instance representing the active record we are joining onto. (So in Author.has_many :posts, the Author would be that base record.)


17
18
19
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 17

def parent
  @parent
end

#reflectionObject (readonly)

The reflection of the association represented


8
9
10
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 8

def reflection
  @reflection
end

#tablesObject (readonly)

Returns the value of attribute tables


25
26
27
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 25

def tables
  @tables
end

Instance Method Details

#==(other) ⇒ Object


50
51
52
53
54
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 50

def ==(other)
  other.class == self.class &&
    other.reflection == reflection &&
    other.parent == parent
end

#aliased_table_nameObject


133
134
135
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 133

def aliased_table_name
  table.table_alias || table.name
end

#build_constraint(reflection, table, key, foreign_table, foreign_key) ⇒ Object


111
112
113
114
115
116
117
118
119
120
121
122
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 111

def build_constraint(reflection, table, key, foreign_table, foreign_key)
  constraint = table[key].eq(foreign_table[foreign_key])

  if reflection.klass.finder_needs_type_condition?
    constraint = table.create_and([
      constraint,
      reflection.klass.send(:type_condition, table)
    ])
  end

  constraint
end

#conditionsObject


137
138
139
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 137

def conditions
  @conditions ||= reflection.conditions.reverse
end

#find_parent_in(other_join_dependency) ⇒ Object


56
57
58
59
60
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 56

def find_parent_in(other_join_dependency)
  other_join_dependency.join_parts.detect do |join_part|
    parent == join_part
  end
end

#join_relation(joining_relation) ⇒ Object


124
125
126
127
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 124

def join_relation(joining_relation)
  self.join_type = Arel::OuterJoin
  joining_relation.joins(self)
end

#join_to(relation) ⇒ Object


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 62

def join_to(relation)
  tables        = @tables.dup
  foreign_table = parent_table
  foreign_klass = parent.active_record

  # The chain starts with the target table, but we want to end with it here (makes
  # more sense in this context), so we reverse
  chain.reverse.each_with_index do |reflection, i|
    table = tables.shift

    case reflection.source_macro
    when :belongs_to
      key         = reflection.association_primary_key
      foreign_key = reflection.foreign_key
    when :has_and_belongs_to_many
      # Join the join table first...
      relation.from(join(
        table,
        table[reflection.foreign_key].
          eq(foreign_table[reflection.active_record_primary_key])
      ))

      foreign_table, table = table, tables.shift

      key         = reflection.association_primary_key
      foreign_key = reflection.association_foreign_key
    else
      key         = reflection.foreign_key
      foreign_key = reflection.active_record_primary_key
    end

    constraint = build_constraint(reflection, table, key, foreign_table, foreign_key)

    conditions = self.conditions[i].dup
    conditions << { reflection.type => foreign_klass.base_class.name } if reflection.type

    unless conditions.empty?
      constraint = constraint.and(sanitize(conditions, table))
    end

    relation.from(join(table, constraint))

    # The current table in this iteration becomes the foreign table in the next
    foreign_table, foreign_klass = table, reflection.klass
  end

  relation
end

#tableObject


129
130
131
# File 'activerecord/lib/active_record/associations/join_dependency/join_association.rb', line 129

def table
  tables.last
end