Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 177 lines (140 sloc) 5.883 kb
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
1 module ActiveRecord
2 module Associations
3 class JoinDependency # :nodoc:
4 class JoinAssociation < JoinPart # :nodoc:
e18679a @jonleighton Abstract some common code from AssociationScope and JoinDependency::J…
jonleighton authored
5 include JoinHelper
6
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
7 # The reflection of the association represented
8 attr_reader :reflection
9
10 # The JoinDependency object which this JoinAssociation exists within. This is mainly
11 # relevant for generating aliases which do not conflict with other joins which are
12 # part of the query.
13 attr_reader :join_dependency
14
15 # A JoinBase instance representing the active record we are joining onto.
16 # (So in Author.has_many :posts, the Author would be that base record.)
17 attr_reader :parent
18
19 # What type of join will be generated, either Arel::InnerJoin (default) or Arel::OuterJoin
20 attr_accessor :join_type
21
22 # These implement abstract methods from the superclass
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
23 attr_reader :aliased_prefix
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
24
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
25 attr_reader :tables
26
2d3d9e3 @jonleighton Rename Reflection#through_reflection_chain and #through_options to Re…
jonleighton authored
27 delegate :options, :through_reflection, :source_reflection, :chain, :to => :reflection
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
28 delegate :table, :table_name, :to => :parent, :prefix => :parent
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
29 delegate :alias_tracker, :to => :join_dependency
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
30
e18679a @jonleighton Abstract some common code from AssociationScope and JoinDependency::J…
jonleighton authored
31 alias :alias_suffix :parent_table_name
32
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
33 def initialize(reflection, join_dependency, parent = nil)
34 reflection.check_validity!
35
36 if reflection.options[:polymorphic]
37 raise EagerLoadPolymorphicError.new(reflection)
38 end
39
40 super(reflection.klass)
41
42 @reflection = reflection
43 @join_dependency = join_dependency
44 @parent = parent
45 @join_type = Arel::InnerJoin
46 @aliased_prefix = "t#{ join_dependency.join_parts.size }"
e18679a @jonleighton Abstract some common code from AssociationScope and JoinDependency::J…
jonleighton authored
47 @tables = construct_tables.reverse
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
48 end
49
50 def ==(other)
51 other.class == self.class &&
52 other.reflection == reflection &&
53 other.parent == parent
54 end
55
56 def find_parent_in(other_join_dependency)
57 other_join_dependency.join_parts.detect do |join_part|
dc764fc @neerajdotname While merging relations preserve context for joins
neerajdotname authored
58 case parent
59 when JoinBase
60 parent.base_klass == join_part.base_klass
61 else
62 parent == join_part
63 end
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
64 end
65 end
66
6303cef @neerajdotname not a relation. it's an arel select manager
neerajdotname authored
67 def join_to(manager)
aef3629 @jonleighton Refactor JoinAssociation
jonleighton authored
68 tables = @tables.dup
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
69 foreign_table = parent_table
d87966c @neerajdotname changed variable name active_record => base_klass
neerajdotname authored
70 foreign_klass = parent.base_klass
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
71
2d3d9e3 @jonleighton Rename Reflection#through_reflection_chain and #through_options to Re…
jonleighton authored
72 # The chain starts with the target table, but we want to end with it here (makes
73 # more sense in this context), so we reverse
aef3629 @jonleighton Refactor JoinAssociation
jonleighton authored
74 chain.reverse.each_with_index do |reflection, i|
75 table = tables.shift
76
77 case reflection.source_macro
78 when :belongs_to
79 key = reflection.association_primary_key
80 foreign_key = reflection.foreign_key
81 when :has_and_belongs_to_many
82 # Join the join table first...
6303cef @neerajdotname not a relation. it's an arel select manager
neerajdotname authored
83 manager.from(join(
aef3629 @jonleighton Refactor JoinAssociation
jonleighton authored
84 table,
85 table[reflection.foreign_key].
86 eq(foreign_table[reflection.active_record_primary_key])
87 ))
88
89 foreign_table, table = table, tables.shift
90
91 key = reflection.association_primary_key
92 foreign_key = reflection.association_foreign_key
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
93 else
aef3629 @jonleighton Refactor JoinAssociation
jonleighton authored
94 key = reflection.foreign_key
95 foreign_key = reflection.active_record_primary_key
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
96 end
97
6b6ecbe @jonleighton Extract the constraint-building for joins in JoinAssociation into a s…
jonleighton authored
98 constraint = build_constraint(reflection, table, key, foreign_table, foreign_key)
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
99
65843e1 @jonleighton Represent association scope options as AR::Relations insternally.
jonleighton authored
100 scope_chain_items = scope_chain[i]
d7a910e @jonleighton Fix problem with loading polymorphic associations which have been def…
jonleighton authored
101
65843e1 @jonleighton Represent association scope options as AR::Relations insternally.
jonleighton authored
102 if reflection.type
103 scope_chain_items += [
104 ActiveRecord::Relation.new(reflection.klass, table)
105 .where(reflection.type => foreign_klass.base_class.name)
106 ]
107 end
108
b407839 @jonleighton Apply default scope when joining associations.
jonleighton authored
109 scope_chain_items += [reflection.klass.send(:build_default_scope)].compact
110
65843e1 @jonleighton Represent association scope options as AR::Relations insternally.
jonleighton authored
111 scope_chain_items.each do |item|
112 unless item.is_a?(Relation)
113 item = ActiveRecord::Relation.new(reflection.klass, table).instance_exec(self, &item)
114 end
f6cc665 @jonleighton Avoid sanitize_sql when we can use Relation#where instead
jonleighton authored
115
65843e1 @jonleighton Represent association scope options as AR::Relations insternally.
jonleighton authored
116 constraint = constraint.and(item.arel.constraints) unless item.arel.constraints.empty?
37d93ea @jonleighton Fix tests under postgres - we should always put conditions in the WHE…
jonleighton authored
117 end
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
118
6303cef @neerajdotname not a relation. it's an arel select manager
neerajdotname authored
119 manager.from(join(table, constraint))
8d270a2 @ernie Add join conditions to JOIN clause, not WHERE
ernie authored
120
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
121 # The current table in this iteration becomes the foreign table in the next
d7a910e @jonleighton Fix problem with loading polymorphic associations which have been def…
jonleighton authored
122 foreign_table, foreign_klass = table, reflection.klass
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
123 end
124
6303cef @neerajdotname not a relation. it's an arel select manager
neerajdotname authored
125 manager
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
126 end
127
070dda2 @neerajdotname rdoc for some of the methods in JoinDependency
neerajdotname authored
128 # Builds equality condition.
129 #
130 # Example:
131 #
132 # class Physician < ActiveRecord::Base
133 # has_many :appointments
134 # end
135 #
136 # If I execute `Physician.joins(:appointments).to_a` then
137 # reflection #=> #<ActiveRecord::Reflection::AssociationReflection @macro=:has_many ...>
138 # table #=> #<Arel::Table @name="appointments" ...>
139 # key #=> physician_id
140 # foreign_table #=> #<Arel::Table @name="physicians" ...>
141 # foreign_key #=> id
142 #
6b6ecbe @jonleighton Extract the constraint-building for joins in JoinAssociation into a s…
jonleighton authored
143 def build_constraint(reflection, table, key, foreign_table, foreign_key)
144 constraint = table[key].eq(foreign_table[foreign_key])
145
146 if reflection.klass.finder_needs_type_condition?
147 constraint = table.create_and([
148 constraint,
149 reflection.klass.send(:type_condition, table)
150 ])
151 end
152
153 constraint
154 end
155
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
156 def join_relation(joining_relation)
157 self.join_type = Arel::OuterJoin
158 joining_relation.joins(self)
159 end
160
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
161 def table
aef3629 @jonleighton Refactor JoinAssociation
jonleighton authored
162 tables.last
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
163 end
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
164
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
165 def aliased_table_name
166 table.table_alias || table.name
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
167 end
168
65843e1 @jonleighton Represent association scope options as AR::Relations insternally.
jonleighton authored
169 def scope_chain
170 @scope_chain ||= reflection.scope_chain.reverse
735844d @jonleighton Merge branch 'master' into nested_has_many_through
jonleighton authored
171 end
b171b9e @jonleighton Move JoinDependency and friends from ActiveRecord::Associations::Clas…
jonleighton authored
172
173 end
174 end
175 end
176 end
Something went wrong with that request. Please try again.