activerecord 3.2.22.5 → 4.2.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (236) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1632 -609
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +37 -41
  5. data/examples/performance.rb +31 -19
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +56 -42
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -36
  10. data/lib/active_record/associations/association.rb +73 -55
  11. data/lib/active_record/associations/association_scope.rb +143 -82
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +125 -31
  15. data/lib/active_record/associations/builder/belongs_to.rb +89 -61
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +23 -17
  21. data/lib/active_record/associations/collection_association.rb +251 -177
  22. data/lib/active_record/associations/collection_proxy.rb +963 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +113 -22
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -39
  26. data/lib/active_record/associations/has_one_association.rb +43 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -107
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +62 -33
  38. data/lib/active_record/associations/preloader.rb +101 -79
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +30 -16
  41. data/lib/active_record/associations.rb +463 -345
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +142 -151
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +137 -57
  47. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +73 -106
  50. data/lib/active_record/attribute_methods/serialization.rb +44 -94
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
  52. data/lib/active_record/attribute_methods/write.rb +57 -44
  53. data/lib/active_record/attribute_methods.rb +301 -141
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +246 -217
  58. data/lib/active_record/base.rb +70 -474
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +396 -219
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +261 -169
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
  75. data/lib/active_record/connection_adapters/column.rb +31 -245
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +430 -999
  114. data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +157 -105
  119. data/lib/active_record/dynamic_matchers.rb +119 -63
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +94 -36
  122. data/lib/active_record/explain.rb +15 -63
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +9 -5
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +302 -215
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +143 -70
  129. data/lib/active_record/integration.rb +65 -12
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +73 -52
  133. data/lib/active_record/locking/pessimistic.rb +5 -5
  134. data/lib/active_record/log_subscriber.rb +24 -21
  135. data/lib/active_record/migration/command_recorder.rb +124 -32
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +511 -213
  138. data/lib/active_record/model_schema.rb +91 -117
  139. data/lib/active_record/nested_attributes.rb +184 -130
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +276 -117
  143. data/lib/active_record/query_cache.rb +19 -37
  144. data/lib/active_record/querying.rb +28 -18
  145. data/lib/active_record/railtie.rb +73 -40
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +4 -3
  148. data/lib/active_record/railties/databases.rake +141 -416
  149. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  150. data/lib/active_record/readonly_attributes.rb +1 -4
  151. data/lib/active_record/reflection.rb +513 -154
  152. data/lib/active_record/relation/batches.rb +91 -43
  153. data/lib/active_record/relation/calculations.rb +199 -161
  154. data/lib/active_record/relation/delegation.rb +116 -25
  155. data/lib/active_record/relation/finder_methods.rb +362 -248
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -43
  160. data/lib/active_record/relation/query_methods.rb +928 -167
  161. data/lib/active_record/relation/spawn_methods.rb +48 -149
  162. data/lib/active_record/relation.rb +352 -207
  163. data/lib/active_record/result.rb +101 -10
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +56 -59
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +106 -63
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +50 -57
  170. data/lib/active_record/scoping/named.rb +73 -109
  171. data/lib/active_record/scoping.rb +58 -123
  172. data/lib/active_record/serialization.rb +6 -2
  173. data/lib/active_record/serializers/xml_serializer.rb +12 -22
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +168 -15
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +23 -16
  181. data/lib/active_record/transactions.rb +125 -79
  182. data/lib/active_record/type/big_integer.rb +13 -0
  183. data/lib/active_record/type/binary.rb +50 -0
  184. data/lib/active_record/type/boolean.rb +31 -0
  185. data/lib/active_record/type/date.rb +50 -0
  186. data/lib/active_record/type/date_time.rb +54 -0
  187. data/lib/active_record/type/decimal.rb +64 -0
  188. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  189. data/lib/active_record/type/decorator.rb +14 -0
  190. data/lib/active_record/type/float.rb +19 -0
  191. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  192. data/lib/active_record/type/integer.rb +59 -0
  193. data/lib/active_record/type/mutable.rb +16 -0
  194. data/lib/active_record/type/numeric.rb +36 -0
  195. data/lib/active_record/type/serialized.rb +62 -0
  196. data/lib/active_record/type/string.rb +40 -0
  197. data/lib/active_record/type/text.rb +11 -0
  198. data/lib/active_record/type/time.rb +26 -0
  199. data/lib/active_record/type/time_value.rb +38 -0
  200. data/lib/active_record/type/type_map.rb +64 -0
  201. data/lib/active_record/type/unsigned_integer.rb +15 -0
  202. data/lib/active_record/type/value.rb +110 -0
  203. data/lib/active_record/type.rb +23 -0
  204. data/lib/active_record/validations/associated.rb +24 -16
  205. data/lib/active_record/validations/presence.rb +67 -0
  206. data/lib/active_record/validations/uniqueness.rb +123 -64
  207. data/lib/active_record/validations.rb +36 -29
  208. data/lib/active_record/version.rb +5 -7
  209. data/lib/active_record.rb +66 -46
  210. data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
  211. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
  212. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  213. data/lib/rails/generators/active_record/migration.rb +11 -8
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
  215. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  216. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  217. data/lib/rails/generators/active_record.rb +3 -11
  218. metadata +101 -45
  219. data/examples/associations.png +0 -0
  220. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  221. data/lib/active_record/associations/join_helper.rb +0 -55
  222. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  223. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  226. data/lib/active_record/dynamic_finder_match.rb +0 -68
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/fixtures/file.rb +0 -65
  229. data/lib/active_record/identity_map.rb +0 -162
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -360
  232. data/lib/active_record/test_case.rb +0 -73
  233. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  234. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  235. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  236. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,158 +1,127 @@
1
+ require 'active_record/associations/join_dependency/join_part'
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class JoinDependency # :nodoc:
4
6
  class JoinAssociation < JoinPart # :nodoc:
5
- include JoinHelper
6
-
7
7
  # The reflection of the association represented
8
8
  attr_reader :reflection
9
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
23
- attr_reader :aliased_prefix
24
-
25
- attr_reader :tables
26
-
27
- delegate :options, :through_reflection, :source_reflection, :chain, :to => :reflection
28
- delegate :table, :table_name, :to => :parent, :prefix => :parent
29
- delegate :alias_tracker, :to => :join_dependency
10
+ attr_accessor :tables
30
11
 
31
- alias :alias_suffix :parent_table_name
32
-
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)
12
+ def initialize(reflection, children)
13
+ super(reflection.klass, children)
41
14
 
42
15
  @reflection = reflection
43
- @join_dependency = join_dependency
44
- @parent = parent
45
- @join_type = Arel::InnerJoin
46
- @aliased_prefix = "t#{ join_dependency.join_parts.size }"
47
- @tables = construct_tables.reverse
16
+ @tables = nil
48
17
  end
49
18
 
50
- def ==(other)
51
- other.class == self.class &&
52
- other.reflection == reflection &&
53
- other.parent == parent
19
+ def match?(other)
20
+ return true if self == other
21
+ super && reflection == other.reflection
54
22
  end
55
23
 
56
- def find_parent_in(other_join_dependency)
57
- other_join_dependency.join_parts.detect do |join_part|
58
- case parent
59
- when JoinBase
60
- parent.active_record == join_part.active_record
61
- else
62
- parent == join_part
63
- end
64
- end
65
- end
24
+ JoinInformation = Struct.new :joins, :binds
66
25
 
67
- def join_to(relation)
68
- tables = @tables.dup
69
- foreign_table = parent_table
70
- foreign_klass = parent.active_record
26
+ def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
27
+ joins = []
28
+ bind_values = []
29
+ tables = tables.reverse
30
+
31
+ scope_chain_index = 0
32
+ scope_chain = scope_chain.reverse
71
33
 
72
34
  # The chain starts with the target table, but we want to end with it here (makes
73
35
  # more sense in this context), so we reverse
74
- chain.reverse.each_with_index do |reflection, i|
36
+ chain.reverse_each do |reflection|
75
37
  table = tables.shift
38
+ klass = reflection.klass
39
+
40
+ join_keys = reflection.join_keys(klass)
41
+ key = join_keys.key
42
+ foreign_key = join_keys.foreign_key
76
43
 
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...
83
- relation.from(join(
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
93
- else
94
- key = reflection.foreign_key
95
- foreign_key = reflection.active_record_primary_key
44
+ constraint = build_constraint(klass, table, key, foreign_table, foreign_key)
45
+
46
+ scope_chain_items = scope_chain[scope_chain_index].map do |item|
47
+ if item.is_a?(Relation)
48
+ item
49
+ else
50
+ ActiveRecord::Relation.create(klass, table).instance_exec(node, &item)
51
+ end
52
+ end
53
+ scope_chain_index += 1
54
+
55
+ klass_scope =
56
+ if klass.current_scope && klass.current_scope.values.blank?
57
+ klass.unscoped
58
+ else
59
+ klass.send(:build_default_scope, ActiveRecord::Relation.create(klass, table))
60
+ end
61
+ scope_chain_items.concat [klass_scope].compact
62
+
63
+ rel = scope_chain_items.inject(scope_chain_items.shift) do |left, right|
64
+ left.merge right
96
65
  end
97
66
 
98
- constraint = build_constraint(reflection, table, key, foreign_table, foreign_key)
67
+ if rel && !rel.arel.constraints.empty?
68
+ bind_values.concat rel.bind_values
69
+ constraint = constraint.and rel.arel.constraints
70
+ end
99
71
 
100
- conditions = self.conditions[i].dup
101
- conditions << { reflection.type => foreign_klass.base_class.name } if reflection.type
72
+ if reflection.type
73
+ value = foreign_klass.base_class.name
74
+ column = klass.columns_hash[reflection.type.to_s]
102
75
 
103
- unless conditions.empty?
104
- constraint = constraint.and(sanitize(conditions, table))
76
+ substitute = klass.connection.substitute_at(column)
77
+ bind_values.push [column, value]
78
+ constraint = constraint.and table[reflection.type].eq substitute
105
79
  end
106
80
 
107
- relation.from(join(table, constraint))
81
+ joins << table.create_join(table, table.create_on(constraint), join_type)
108
82
 
109
83
  # The current table in this iteration becomes the foreign table in the next
110
- foreign_table, foreign_klass = table, reflection.klass
84
+ foreign_table, foreign_klass = table, klass
111
85
  end
112
86
 
113
- relation
87
+ JoinInformation.new joins, bind_values
114
88
  end
115
89
 
116
- def build_constraint(reflection, table, key, foreign_table, foreign_key)
90
+ # Builds equality condition.
91
+ #
92
+ # Example:
93
+ #
94
+ # class Physician < ActiveRecord::Base
95
+ # has_many :appointments
96
+ # end
97
+ #
98
+ # If I execute `Physician.joins(:appointments).to_a` then
99
+ # klass # => Physician
100
+ # table # => #<Arel::Table @name="appointments" ...>
101
+ # key # => physician_id
102
+ # foreign_table # => #<Arel::Table @name="physicians" ...>
103
+ # foreign_key # => id
104
+ #
105
+ def build_constraint(klass, table, key, foreign_table, foreign_key)
117
106
  constraint = table[key].eq(foreign_table[foreign_key])
118
107
 
119
- if reflection.klass.finder_needs_type_condition?
108
+ if klass.finder_needs_type_condition?
120
109
  constraint = table.create_and([
121
110
  constraint,
122
- reflection.klass.send(:type_condition, table)
111
+ klass.send(:type_condition, table)
123
112
  ])
124
113
  end
125
114
 
126
115
  constraint
127
116
  end
128
117
 
129
- def join_relation(joining_relation)
130
- self.join_type = Arel::OuterJoin
131
- joining_relation.joins(self)
132
- end
133
-
134
118
  def table
135
- tables.last
119
+ tables.first
136
120
  end
137
121
 
138
122
  def aliased_table_name
139
123
  table.table_alias || table.name
140
124
  end
141
-
142
- def conditions
143
- @conditions ||= reflection.conditions.reverse
144
- end
145
-
146
- private
147
-
148
- def interpolate(conditions)
149
- if conditions.respond_to?(:to_proc) && !conditions.is_a?(Hash)
150
- instance_eval(&conditions)
151
- else
152
- conditions
153
- end
154
- end
155
-
156
125
  end
157
126
  end
158
127
  end
@@ -1,22 +1,20 @@
1
+ require 'active_record/associations/join_dependency/join_part'
2
+
1
3
  module ActiveRecord
2
4
  module Associations
3
5
  class JoinDependency # :nodoc:
4
6
  class JoinBase < JoinPart # :nodoc:
5
- def ==(other)
6
- other.class == self.class &&
7
- other.active_record == active_record
8
- end
9
-
10
- def aliased_prefix
11
- "t0"
7
+ def match?(other)
8
+ return true if self == other
9
+ super && base_klass == other.base_klass
12
10
  end
13
11
 
14
12
  def table
15
- Arel::Table.new(table_name, arel_engine)
13
+ base_klass.arel_table
16
14
  end
17
15
 
18
16
  def aliased_table_name
19
- active_record.table_name
17
+ base_klass.table_name
20
18
  end
21
19
  end
22
20
  end
@@ -1,41 +1,42 @@
1
1
  module ActiveRecord
2
2
  module Associations
3
3
  class JoinDependency # :nodoc:
4
- # A JoinPart represents a part of a JoinDependency. It is an abstract class, inherited
4
+ # A JoinPart represents a part of a JoinDependency. It is inherited
5
5
  # by JoinBase and JoinAssociation. A JoinBase represents the Active Record which
6
6
  # everything else is being joined onto. A JoinAssociation represents an association which
7
7
  # is joining to the base. A JoinAssociation may result in more than one actual join
8
8
  # operations (for example a has_and_belongs_to_many JoinAssociation would result in
9
9
  # two; one for the join table and one for the target table).
10
10
  class JoinPart # :nodoc:
11
+ include Enumerable
12
+
11
13
  # The Active Record class which this join part is associated 'about'; for a JoinBase
12
14
  # this is the actual base model, for a JoinAssociation this is the target model of the
13
15
  # association.
14
- attr_reader :active_record
16
+ attr_reader :base_klass, :children
15
17
 
16
- delegate :table_name, :column_names, :primary_key, :reflections, :arel_engine, :to => :active_record
18
+ delegate :table_name, :column_names, :primary_key, :to => :base_klass
17
19
 
18
- def initialize(active_record)
19
- @active_record = active_record
20
- @cached_record = {}
21
- @column_names_with_alias = nil
20
+ def initialize(base_klass, children)
21
+ @base_klass = base_klass
22
+ @children = children
22
23
  end
23
24
 
24
- def aliased_table
25
- Arel::Nodes::TableAlias.new table, aliased_table_name
25
+ def name
26
+ reflection.name
26
27
  end
27
28
 
28
- def ==(other)
29
- raise NotImplementedError
29
+ def match?(other)
30
+ self.class == other.class
30
31
  end
31
32
 
32
- # An Arel::Table for the active_record
33
- def table
34
- raise NotImplementedError
33
+ def each(&block)
34
+ yield self
35
+ children.each { |child| child.each(&block) }
35
36
  end
36
37
 
37
- # The prefix to be used when aliasing columns in the active_record's table
38
- def aliased_prefix
38
+ # An Arel::Table for the active_record
39
+ def table
39
40
  raise NotImplementedError
40
41
  end
41
42
 
@@ -44,33 +45,25 @@ module ActiveRecord
44
45
  raise NotImplementedError
45
46
  end
46
47
 
47
- # The alias for the primary key of the active_record's table
48
- def aliased_primary_key
49
- "#{aliased_prefix}_r0"
50
- end
48
+ def extract_record(row, column_names_with_alias)
49
+ # This code is performance critical as it is called per row.
50
+ # see: https://github.com/rails/rails/pull/12185
51
+ hash = {}
51
52
 
52
- # An array of [column_name, alias] pairs for the table
53
- def column_names_with_alias
54
- unless @column_names_with_alias
55
- @column_names_with_alias = []
53
+ index = 0
54
+ length = column_names_with_alias.length
56
55
 
57
- ([primary_key] + (column_names - [primary_key])).each_with_index do |column_name, i|
58
- @column_names_with_alias << [column_name, "#{aliased_prefix}_r#{i}"]
59
- end
56
+ while index < length
57
+ column_name, alias_name = column_names_with_alias[index]
58
+ hash[column_name] = row[alias_name]
59
+ index += 1
60
60
  end
61
- @column_names_with_alias
62
- end
63
-
64
- def extract_record(row)
65
- Hash[column_names_with_alias.map{|cn, an| [cn, row[an]]}]
66
- end
67
61
 
68
- def record_id(row)
69
- row[aliased_primary_key]
62
+ hash
70
63
  end
71
64
 
72
- def instantiate(row)
73
- @cached_record[record_id(row)] ||= active_record.send(:instantiate, extract_record(row))
65
+ def instantiate(row, aliases)
66
+ base_klass.instantiate(extract_record(row, aliases))
74
67
  end
75
68
  end
76
69
  end