activerecord 3.1.10 → 4.2.11

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 (237) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +1837 -338
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +39 -43
  5. data/examples/performance.rb +51 -20
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +57 -43
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -39
  10. data/lib/active_record/associations/association.rb +71 -85
  11. data/lib/active_record/associations/association_scope.rb +138 -89
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
  14. data/lib/active_record/associations/builder/association.rb +125 -29
  15. data/lib/active_record/associations/builder/belongs_to.rb +91 -60
  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 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +22 -29
  21. data/lib/active_record/associations/collection_association.rb +294 -187
  22. data/lib/active_record/associations/collection_proxy.rb +961 -94
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +118 -23
  25. data/lib/active_record/associations/has_many_through_association.rb +115 -45
  26. data/lib/active_record/associations/has_one_association.rb +57 -24
  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 -102
  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 +61 -32
  38. data/lib/active_record/associations/preloader.rb +113 -87
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +37 -19
  41. data/lib/active_record/associations.rb +505 -371
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +212 -0
  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 +141 -51
  47. data/lib/active_record/attribute_methods/primary_key.rb +87 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +74 -117
  50. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
  52. data/lib/active_record/attribute_methods/write.rb +60 -21
  53. data/lib/active_record/attribute_methods.rb +409 -48
  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 +279 -232
  58. data/lib/active_record/base.rb +84 -1969
  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 +422 -243
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
  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 +273 -170
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
  75. data/lib/active_record/connection_adapters/column.rb +33 -221
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
  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 +445 -902
  114. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
  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 +159 -102
  119. data/lib/active_record/dynamic_matchers.rb +140 -0
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +102 -34
  122. data/lib/active_record/explain.rb +38 -0
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +29 -0
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +318 -260
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +247 -0
  129. data/lib/active_record/integration.rb +113 -0
  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 +80 -52
  133. data/lib/active_record/locking/pessimistic.rb +27 -5
  134. data/lib/active_record/log_subscriber.rb +25 -18
  135. data/lib/active_record/migration/command_recorder.rb +130 -38
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +532 -201
  138. data/lib/active_record/model_schema.rb +342 -0
  139. data/lib/active_record/nested_attributes.rb +229 -139
  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 +304 -99
  143. data/lib/active_record/query_cache.rb +25 -43
  144. data/lib/active_record/querying.rb +68 -0
  145. data/lib/active_record/railtie.rb +86 -45
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +7 -4
  148. data/lib/active_record/railties/databases.rake +198 -377
  149. data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
  150. data/lib/active_record/readonly_attributes.rb +23 -0
  151. data/lib/active_record/reflection.rb +516 -165
  152. data/lib/active_record/relation/batches.rb +96 -45
  153. data/lib/active_record/relation/calculations.rb +221 -144
  154. data/lib/active_record/relation/delegation.rb +140 -0
  155. data/lib/active_record/relation/finder_methods.rb +362 -243
  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 -41
  160. data/lib/active_record/relation/query_methods.rb +982 -155
  161. data/lib/active_record/relation/spawn_methods.rb +50 -110
  162. data/lib/active_record/relation.rb +371 -180
  163. data/lib/active_record/result.rb +109 -12
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +191 -0
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +111 -61
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +135 -0
  170. data/lib/active_record/scoping/named.rb +164 -0
  171. data/lib/active_record/scoping.rb +87 -0
  172. data/lib/active_record/serialization.rb +7 -45
  173. data/lib/active_record/serializers/xml_serializer.rb +14 -65
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +205 -0
  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 +35 -14
  181. data/lib/active_record/transactions.rb +141 -74
  182. data/lib/active_record/translation.rb +22 -0
  183. data/lib/active_record/type/big_integer.rb +13 -0
  184. data/lib/active_record/type/binary.rb +50 -0
  185. data/lib/active_record/type/boolean.rb +31 -0
  186. data/lib/active_record/type/date.rb +50 -0
  187. data/lib/active_record/type/date_time.rb +54 -0
  188. data/lib/active_record/type/decimal.rb +64 -0
  189. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  190. data/lib/active_record/type/decorator.rb +14 -0
  191. data/lib/active_record/type/float.rb +19 -0
  192. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  193. data/lib/active_record/type/integer.rb +59 -0
  194. data/lib/active_record/type/mutable.rb +16 -0
  195. data/lib/active_record/type/numeric.rb +36 -0
  196. data/lib/active_record/type/serialized.rb +62 -0
  197. data/lib/active_record/type/string.rb +40 -0
  198. data/lib/active_record/type/text.rb +11 -0
  199. data/lib/active_record/type/time.rb +26 -0
  200. data/lib/active_record/type/time_value.rb +38 -0
  201. data/lib/active_record/type/type_map.rb +64 -0
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type/value.rb +110 -0
  204. data/lib/active_record/type.rb +23 -0
  205. data/lib/active_record/validations/associated.rb +27 -18
  206. data/lib/active_record/validations/presence.rb +67 -0
  207. data/lib/active_record/validations/uniqueness.rb +125 -66
  208. data/lib/active_record/validations.rb +37 -30
  209. data/lib/active_record/version.rb +5 -7
  210. data/lib/active_record.rb +80 -25
  211. data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
  212. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  213. data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
  214. data/lib/rails/generators/active_record/migration.rb +11 -8
  215. data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
  216. data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
  217. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  218. data/lib/rails/generators/active_record.rb +3 -11
  219. metadata +132 -53
  220. data/examples/associations.png +0 -0
  221. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
  222. data/lib/active_record/associations/join_helper.rb +0 -55
  223. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
  226. data/lib/active_record/dynamic_finder_match.rb +0 -56
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/identity_map.rb +0 -163
  229. data/lib/active_record/named_scope.rb +0 -200
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -358
  232. data/lib/active_record/test_case.rb +0 -69
  233. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
  234. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  235. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  236. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  237. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -1,153 +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
- parent == join_part
59
- end
60
- end
24
+ JoinInformation = Struct.new :joins, :binds
25
+
26
+ def join_constraints(foreign_table, foreign_klass, node, join_type, tables, scope_chain, chain)
27
+ joins = []
28
+ bind_values = []
29
+ tables = tables.reverse
61
30
 
62
- def join_to(relation)
63
- tables = @tables.dup
64
- foreign_table = parent_table
65
- foreign_klass = parent.active_record
31
+ scope_chain_index = 0
32
+ scope_chain = scope_chain.reverse
66
33
 
67
34
  # The chain starts with the target table, but we want to end with it here (makes
68
35
  # more sense in this context), so we reverse
69
- chain.reverse.each_with_index do |reflection, i|
36
+ chain.reverse_each do |reflection|
70
37
  table = tables.shift
38
+ klass = reflection.klass
71
39
 
72
- case reflection.source_macro
73
- when :belongs_to
74
- key = reflection.association_primary_key
75
- foreign_key = reflection.foreign_key
76
- when :has_and_belongs_to_many
77
- # Join the join table first...
78
- relation.from(join(
79
- table,
80
- table[reflection.foreign_key].
81
- eq(foreign_table[reflection.active_record_primary_key])
82
- ))
83
-
84
- foreign_table, table = table, tables.shift
85
-
86
- key = reflection.association_primary_key
87
- foreign_key = reflection.association_foreign_key
88
- else
89
- key = reflection.foreign_key
90
- foreign_key = reflection.active_record_primary_key
40
+ join_keys = reflection.join_keys(klass)
41
+ key = join_keys.key
42
+ foreign_key = join_keys.foreign_key
43
+
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
91
65
  end
92
66
 
93
- 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
94
71
 
95
- conditions = self.conditions[i].dup
96
- 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]
97
75
 
98
- unless conditions.empty?
99
- 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
100
79
  end
101
80
 
102
- relation.from(join(table, constraint))
81
+ joins << table.create_join(table, table.create_on(constraint), join_type)
103
82
 
104
83
  # The current table in this iteration becomes the foreign table in the next
105
- foreign_table, foreign_klass = table, reflection.klass
84
+ foreign_table, foreign_klass = table, klass
106
85
  end
107
86
 
108
- relation
87
+ JoinInformation.new joins, bind_values
109
88
  end
110
89
 
111
- 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)
112
106
  constraint = table[key].eq(foreign_table[foreign_key])
113
107
 
114
- if reflection.klass.finder_needs_type_condition?
108
+ if klass.finder_needs_type_condition?
115
109
  constraint = table.create_and([
116
110
  constraint,
117
- reflection.klass.send(:type_condition, table)
111
+ klass.send(:type_condition, table)
118
112
  ])
119
113
  end
120
114
 
121
115
  constraint
122
116
  end
123
117
 
124
- def join_relation(joining_relation)
125
- self.join_type = Arel::OuterJoin
126
- joining_relation.joins(self)
127
- end
128
-
129
118
  def table
130
- tables.last
119
+ tables.first
131
120
  end
132
121
 
133
122
  def aliased_table_name
134
123
  table.table_alias || table.name
135
124
  end
136
-
137
- def conditions
138
- @conditions ||= reflection.conditions.reverse
139
- end
140
-
141
- private
142
-
143
- def interpolate(conditions)
144
- if conditions.respond_to?(:to_proc)
145
- instance_eval(&conditions)
146
- else
147
- conditions
148
- end
149
- end
150
-
151
125
  end
152
126
  end
153
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