activerecord 5.1.5 → 5.2.8.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +655 -608
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record/aggregations.rb +6 -5
  8. data/lib/active_record/association_relation.rb +7 -5
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +41 -37
  11. data/lib/active_record/associations/association_scope.rb +38 -50
  12. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +4 -7
  15. data/lib/active_record/associations/builder/belongs_to.rb +14 -5
  16. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  18. data/lib/active_record/associations/builder/has_many.rb +2 -0
  19. data/lib/active_record/associations/builder/has_one.rb +2 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  21. data/lib/active_record/associations/collection_association.rb +59 -47
  22. data/lib/active_record/associations/collection_proxy.rb +20 -49
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +12 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  26. data/lib/active_record/associations/has_one_association.rb +12 -1
  27. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  28. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  29. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  30. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  31. data/lib/active_record/associations/join_dependency.rb +48 -93
  32. data/lib/active_record/associations/preloader/association.rb +45 -61
  33. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/singular_association.rb +14 -16
  36. data/lib/active_record/associations/through_association.rb +26 -11
  37. data/lib/active_record/associations.rb +40 -63
  38. data/lib/active_record/attribute_assignment.rb +2 -5
  39. data/lib/active_record/attribute_decorators.rb +3 -2
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  41. data/lib/active_record/attribute_methods/dirty.rb +32 -216
  42. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  43. data/lib/active_record/attribute_methods/query.rb +2 -0
  44. data/lib/active_record/attribute_methods/read.rb +9 -3
  45. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  47. data/lib/active_record/attribute_methods/write.rb +21 -9
  48. data/lib/active_record/attribute_methods.rb +65 -24
  49. data/lib/active_record/attributes.rb +7 -6
  50. data/lib/active_record/autosave_association.rb +35 -19
  51. data/lib/active_record/base.rb +2 -0
  52. data/lib/active_record/callbacks.rb +12 -6
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +15 -1
  55. data/lib/active_record/collection_cache_key.rb +12 -8
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +142 -42
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -32
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +110 -173
  69. data/lib/active_record/connection_adapters/column.rb +3 -1
  70. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  72. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +13 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -3
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -2
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -112
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +66 -74
  117. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +24 -1
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +82 -95
  126. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  127. data/lib/active_record/connection_handling.rb +4 -2
  128. data/lib/active_record/core.rb +51 -61
  129. data/lib/active_record/counter_cache.rb +20 -15
  130. data/lib/active_record/define_callbacks.rb +5 -3
  131. data/lib/active_record/dynamic_matchers.rb +9 -9
  132. data/lib/active_record/enum.rb +18 -13
  133. data/lib/active_record/errors.rb +60 -15
  134. data/lib/active_record/explain.rb +3 -1
  135. data/lib/active_record/explain_registry.rb +2 -0
  136. data/lib/active_record/explain_subscriber.rb +2 -0
  137. data/lib/active_record/fixture_set/file.rb +2 -0
  138. data/lib/active_record/fixtures.rb +67 -60
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +49 -19
  141. data/lib/active_record/integration.rb +58 -19
  142. data/lib/active_record/internal_metadata.rb +2 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  144. data/lib/active_record/locking/optimistic.rb +30 -42
  145. data/lib/active_record/locking/pessimistic.rb +9 -6
  146. data/lib/active_record/log_subscriber.rb +43 -0
  147. data/lib/active_record/migration/command_recorder.rb +11 -9
  148. data/lib/active_record/migration/compatibility.rb +47 -9
  149. data/lib/active_record/migration/join_table.rb +2 -0
  150. data/lib/active_record/migration.rb +189 -139
  151. data/lib/active_record/model_schema.rb +19 -24
  152. data/lib/active_record/nested_attributes.rb +18 -6
  153. data/lib/active_record/no_touching.rb +3 -1
  154. data/lib/active_record/null_relation.rb +2 -0
  155. data/lib/active_record/persistence.rb +198 -49
  156. data/lib/active_record/query_cache.rb +12 -14
  157. data/lib/active_record/querying.rb +4 -2
  158. data/lib/active_record/railtie.rb +80 -6
  159. data/lib/active_record/railties/console_sandbox.rb +2 -0
  160. data/lib/active_record/railties/controller_runtime.rb +2 -0
  161. data/lib/active_record/railties/databases.rake +46 -36
  162. data/lib/active_record/readonly_attributes.rb +3 -2
  163. data/lib/active_record/reflection.rb +108 -194
  164. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  165. data/lib/active_record/relation/batches.rb +20 -5
  166. data/lib/active_record/relation/calculations.rb +46 -20
  167. data/lib/active_record/relation/delegation.rb +45 -27
  168. data/lib/active_record/relation/finder_methods.rb +77 -78
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +53 -23
  171. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  172. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  173. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  174. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  175. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  176. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  177. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  178. data/lib/active_record/relation/predicate_builder.rb +60 -79
  179. data/lib/active_record/relation/query_attribute.rb +28 -2
  180. data/lib/active_record/relation/query_methods.rb +129 -100
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +4 -2
  183. data/lib/active_record/relation/where_clause.rb +65 -68
  184. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  185. data/lib/active_record/relation.rb +120 -214
  186. data/lib/active_record/result.rb +2 -0
  187. data/lib/active_record/runtime_registry.rb +2 -0
  188. data/lib/active_record/sanitization.rb +129 -121
  189. data/lib/active_record/schema.rb +4 -2
  190. data/lib/active_record/schema_dumper.rb +36 -26
  191. data/lib/active_record/schema_migration.rb +2 -0
  192. data/lib/active_record/scoping/default.rb +8 -9
  193. data/lib/active_record/scoping/named.rb +23 -7
  194. data/lib/active_record/scoping.rb +9 -8
  195. data/lib/active_record/secure_token.rb +2 -0
  196. data/lib/active_record/serialization.rb +2 -0
  197. data/lib/active_record/statement_cache.rb +23 -13
  198. data/lib/active_record/store.rb +3 -1
  199. data/lib/active_record/suppressor.rb +2 -0
  200. data/lib/active_record/table_metadata.rb +12 -3
  201. data/lib/active_record/tasks/database_tasks.rb +26 -15
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  204. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  205. data/lib/active_record/timestamp.rb +13 -6
  206. data/lib/active_record/touch_later.rb +2 -0
  207. data/lib/active_record/transactions.rb +33 -28
  208. data/lib/active_record/translation.rb +2 -0
  209. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  210. data/lib/active_record/type/date.rb +2 -0
  211. data/lib/active_record/type/date_time.rb +2 -0
  212. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  213. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  214. data/lib/active_record/type/internal/timezone.rb +2 -0
  215. data/lib/active_record/type/json.rb +30 -0
  216. data/lib/active_record/type/serialized.rb +6 -0
  217. data/lib/active_record/type/text.rb +2 -0
  218. data/lib/active_record/type/time.rb +2 -0
  219. data/lib/active_record/type/type_map.rb +2 -0
  220. data/lib/active_record/type/unsigned_integer.rb +2 -0
  221. data/lib/active_record/type.rb +4 -1
  222. data/lib/active_record/type_caster/connection.rb +2 -0
  223. data/lib/active_record/type_caster/map.rb +3 -1
  224. data/lib/active_record/type_caster.rb +2 -0
  225. data/lib/active_record/validations/absence.rb +2 -0
  226. data/lib/active_record/validations/associated.rb +2 -0
  227. data/lib/active_record/validations/length.rb +2 -0
  228. data/lib/active_record/validations/presence.rb +2 -0
  229. data/lib/active_record/validations/uniqueness.rb +36 -6
  230. data/lib/active_record/validations.rb +2 -0
  231. data/lib/active_record/version.rb +2 -0
  232. data/lib/active_record.rb +11 -4
  233. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  234. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  235. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  236. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  237. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  238. data/lib/rails/generators/active_record/migration.rb +2 -0
  239. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  240. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  241. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record.rb +3 -1
  243. metadata +26 -40
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  252. data/lib/active_record/attribute.rb +0 -240
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -114
  254. data/lib/active_record/attribute_set/builder.rb +0 -124
  255. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  256. data/lib/active_record/attribute_set.rb +0 -113
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,6 +1,7 @@
1
- require "thread"
1
+ # frozen_string_literal: true
2
+
2
3
  require "active_support/core_ext/string/filters"
3
- require "active_support/deprecation"
4
+ require "concurrent/map"
4
5
 
5
6
  module ActiveRecord
6
7
  # = Active Record Reflection
@@ -8,10 +9,8 @@ module ActiveRecord
8
9
  extend ActiveSupport::Concern
9
10
 
10
11
  included do
11
- class_attribute :_reflections, instance_writer: false
12
- class_attribute :aggregate_reflections, instance_writer: false
13
- self._reflections = {}
14
- self.aggregate_reflections = {}
12
+ class_attribute :_reflections, instance_writer: false, default: {}
13
+ class_attribute :aggregate_reflections, instance_writer: false, default: {}
15
14
  end
16
15
 
17
16
  def self.create(macro, name, scope, options, ar)
@@ -139,7 +138,7 @@ module ActiveRecord
139
138
  # HasAndBelongsToManyReflection
140
139
  # ThroughReflection
141
140
  # PolymorphicReflection
142
- # RuntimeReflection
141
+ # RuntimeReflection
143
142
  class AbstractReflection # :nodoc:
144
143
  def through_reflection?
145
144
  false
@@ -155,14 +154,6 @@ module ActiveRecord
155
154
  klass.new(attributes, &block)
156
155
  end
157
156
 
158
- def quoted_table_name
159
- klass.quoted_table_name
160
- end
161
-
162
- def primary_key_type
163
- klass.type_for_attribute(klass.primary_key)
164
- end
165
-
166
157
  # Returns the class name for the macro.
167
158
  #
168
159
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
@@ -174,7 +165,7 @@ module ActiveRecord
174
165
  JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
175
166
 
176
167
  def join_keys
177
- get_join_keys klass
168
+ @join_keys ||= get_join_keys(klass)
178
169
  end
179
170
 
180
171
  # Returns a list of scopes that should be applied for this Reflection
@@ -183,22 +174,30 @@ module ActiveRecord
183
174
  scope ? [scope] : []
184
175
  end
185
176
 
186
- def scope_chain
187
- chain.map(&:scopes)
188
- end
189
- deprecate :scope_chain
190
-
191
- def join_scope(table)
177
+ def join_scope(table, foreign_table, foreign_klass)
192
178
  predicate_builder = predicate_builder(table)
193
179
  scope_chain_items = join_scopes(table, predicate_builder)
194
180
  klass_scope = klass_join_scope(table, predicate_builder)
195
181
 
196
- scope_chain_items.inject(klass_scope || scope_chain_items.shift, &:merge!)
182
+ key = join_keys.key
183
+ foreign_key = join_keys.foreign_key
184
+
185
+ klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
186
+
187
+ if type
188
+ klass_scope.where!(type => foreign_klass.polymorphic_name)
189
+ end
190
+
191
+ if klass.finder_needs_type_condition?
192
+ klass_scope.where!(klass.send(:type_condition, table))
193
+ end
194
+
195
+ scope_chain_items.inject(klass_scope, &:merge!)
197
196
  end
198
197
 
199
198
  def join_scopes(table, predicate_builder) # :nodoc:
200
199
  if scope
201
- [build_scope(table, predicate_builder).instance_exec(&scope)]
200
+ [scope_for(build_scope(table, predicate_builder))]
202
201
  else
203
202
  []
204
203
  end
@@ -210,7 +209,7 @@ module ActiveRecord
210
209
  end
211
210
 
212
211
  def constraints
213
- chain.map(&:scopes).flatten
212
+ chain.flat_map(&:scopes)
214
213
  end
215
214
 
216
215
  def counter_cache_column
@@ -284,24 +283,37 @@ module ActiveRecord
284
283
  end
285
284
 
286
285
  def get_join_keys(association_klass)
287
- JoinKeys.new(join_pk(association_klass), join_fk)
286
+ JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
288
287
  end
289
288
 
290
289
  def build_scope(table, predicate_builder = predicate_builder(table))
291
- Relation.create(klass, table, predicate_builder)
290
+ Relation.create(
291
+ klass,
292
+ table: table,
293
+ predicate_builder: predicate_builder
294
+ )
295
+ end
296
+
297
+ def join_primary_key(*)
298
+ foreign_key
299
+ end
300
+
301
+ def join_foreign_key
302
+ active_record_primary_key
292
303
  end
293
304
 
305
+ protected
306
+ def actual_source_reflection # FIXME: this is a horrible name
307
+ self
308
+ end
309
+
294
310
  private
295
311
  def predicate_builder(table)
296
312
  PredicateBuilder.new(TableMetadata.new(klass, table))
297
313
  end
298
314
 
299
- def join_pk(_)
300
- foreign_key
301
- end
302
-
303
- def join_fk
304
- active_record_primary_key
315
+ def primary_key(klass)
316
+ klass.primary_key || raise(UnknownPrimaryKey.new(klass))
305
317
  end
306
318
  end
307
319
 
@@ -348,6 +360,17 @@ module ActiveRecord
348
360
  #
349
361
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns the Money class
350
362
  # <tt>has_many :clients</tt> returns the Client class
363
+ #
364
+ # class Company < ActiveRecord::Base
365
+ # has_many :clients
366
+ # end
367
+ #
368
+ # Company.reflect_on_association(:clients).klass
369
+ # # => Client
370
+ #
371
+ # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
372
+ # a new association object. Use +build_association+ or +create_association+
373
+ # instead. This allows plugins to hook into association object creation.
351
374
  def klass
352
375
  @klass ||= compute_class(class_name)
353
376
  end
@@ -366,8 +389,8 @@ module ActiveRecord
366
389
  active_record == other_aggregation.active_record
367
390
  end
368
391
 
369
- def scope_for(klass)
370
- scope ? klass.unscoped.instance_exec(nil, &scope) : klass.unscoped
392
+ def scope_for(relation, owner = nil)
393
+ relation.instance_exec(owner, &scope) || relation
371
394
  end
372
395
 
373
396
  private
@@ -388,23 +411,10 @@ module ActiveRecord
388
411
  # Holds all the metadata about an association as it was specified in the
389
412
  # Active Record class.
390
413
  class AssociationReflection < MacroReflection #:nodoc:
391
- # Returns the target association's class.
392
- #
393
- # class Author < ActiveRecord::Base
394
- # has_many :books
395
- # end
396
- #
397
- # Author.reflect_on_association(:books).klass
398
- # # => Book
399
- #
400
- # <b>Note:</b> Do not call +klass.new+ or +klass.create+ to instantiate
401
- # a new association object. Use +build_association+ or +create_association+
402
- # instead. This allows plugins to hook into association object creation.
403
- def klass
404
- @klass ||= compute_class(class_name)
405
- end
406
-
407
414
  def compute_class(name)
415
+ if polymorphic?
416
+ raise ArgumentError, "Polymorphic association does not support to compute class."
417
+ end
408
418
  active_record.send(:compute_type, name)
409
419
  end
410
420
 
@@ -414,31 +424,21 @@ module ActiveRecord
414
424
  def initialize(name, scope, options, active_record)
415
425
  super
416
426
  @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
417
- @foreign_type = options[:foreign_type] || "#{name}_type"
427
+ @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
418
428
  @constructable = calculate_constructable(macro, options)
419
- @association_scope_cache = {}
420
- @scope_lock = Mutex.new
429
+ @association_scope_cache = Concurrent::Map.new
421
430
 
422
431
  if options[:class_name] && options[:class_name].class == Class
423
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
424
- Passing a class to the `class_name` is deprecated and will raise
425
- an ArgumentError in Rails 5.2. It eagerloads more classes than
426
- necessary and potentially creates circular dependencies.
427
-
428
- Please pass the class name as a string:
429
- `#{macro} :#{name}, class_name: '#{options[:class_name]}'`
430
- MSG
432
+ raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
431
433
  end
432
434
  end
433
435
 
434
- def association_scope_cache(conn, owner)
436
+ def association_scope_cache(conn, owner, &block)
435
437
  key = conn.prepared_statements
436
438
  if polymorphic?
437
439
  key = [key, owner._read_attribute(@foreign_type)]
438
440
  end
439
- @association_scope_cache[key] ||= @scope_lock.synchronize {
440
- @association_scope_cache[key] ||= yield
441
- }
441
+ @association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
442
442
  end
443
443
 
444
444
  def constructable? # :nodoc:
@@ -462,10 +462,6 @@ module ActiveRecord
462
462
  options[:primary_key] || primary_key(klass || self.klass)
463
463
  end
464
464
 
465
- def association_primary_key_type
466
- klass.type_for_attribute(association_primary_key.to_s)
467
- end
468
-
469
465
  def active_record_primary_key
470
466
  @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
471
467
  end
@@ -488,7 +484,7 @@ module ActiveRecord
488
484
  alias :check_eager_loadable! :check_preloadable!
489
485
 
490
486
  def join_id_for(owner) # :nodoc:
491
- owner[active_record_primary_key]
487
+ owner[join_foreign_key]
492
488
  end
493
489
 
494
490
  def through_reflection
@@ -571,7 +567,7 @@ module ActiveRecord
571
567
  end
572
568
 
573
569
  VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
574
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key]
570
+ INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
575
571
 
576
572
  def add_as_source(seed)
577
573
  seed
@@ -589,12 +585,6 @@ module ActiveRecord
589
585
  Array(options[:extend])
590
586
  end
591
587
 
592
- protected
593
-
594
- def actual_source_reflection # FIXME: this is a horrible name
595
- self
596
- end
597
-
598
588
  private
599
589
 
600
590
  def calculate_constructable(macro, options)
@@ -635,12 +625,9 @@ module ActiveRecord
635
625
  # +automatic_inverse_of+ method is a valid reflection. We must
636
626
  # make sure that the reflection's active_record name matches up
637
627
  # with the current reflection's klass name.
638
- #
639
- # Note: klass will always be valid because when there's a NameError
640
- # from calling +klass+, +reflection+ will already be set to false.
641
628
  def valid_inverse_reflection?(reflection)
642
629
  reflection &&
643
- klass.name == reflection.active_record.name &&
630
+ klass <= reflection.active_record &&
644
631
  can_find_inverse_of_automatically?(reflection)
645
632
  end
646
633
 
@@ -648,9 +635,8 @@ module ActiveRecord
648
635
  # us from being able to guess the inverse automatically. First, the
649
636
  # <tt>inverse_of</tt> option cannot be set to false. Second, we must
650
637
  # have <tt>has_many</tt>, <tt>has_one</tt>, <tt>belongs_to</tt> associations.
651
- # Third, we must not have options such as <tt>:polymorphic</tt> or
652
- # <tt>:foreign_key</tt> which prevent us from correctly guessing the
653
- # inverse association.
638
+ # Third, we must not have options such as <tt>:foreign_key</tt>
639
+ # which prevent us from correctly guessing the inverse association.
654
640
  #
655
641
  # Anything with a scope can additionally ruin our attempt at finding an
656
642
  # inverse, so we exclude reflections with scopes.
@@ -680,10 +666,6 @@ module ActiveRecord
680
666
  def derive_join_table
681
667
  ModelSchema.derive_join_table_name active_record.table_name, klass.table_name
682
668
  end
683
-
684
- def primary_key(klass)
685
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
686
- end
687
669
  end
688
670
 
689
671
  class HasManyReflection < AssociationReflection # :nodoc:
@@ -737,30 +719,25 @@ module ActiveRecord
737
719
  end
738
720
  end
739
721
 
740
- def join_id_for(owner) # :nodoc:
741
- owner[foreign_key]
722
+ def join_primary_key(klass = nil)
723
+ polymorphic? ? association_primary_key(klass) : association_primary_key
724
+ end
725
+
726
+ def join_foreign_key
727
+ foreign_key
742
728
  end
743
729
 
744
730
  private
731
+ def can_find_inverse_of_automatically?(_)
732
+ !polymorphic? && super
733
+ end
745
734
 
746
735
  def calculate_constructable(macro, options)
747
736
  !polymorphic?
748
737
  end
749
-
750
- def join_fk
751
- foreign_key
752
- end
753
-
754
- def join_pk(klass)
755
- polymorphic? ? association_primary_key(klass) : association_primary_key
756
- end
757
738
  end
758
739
 
759
740
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
760
- def initialize(name, scope, options, active_record)
761
- super
762
- end
763
-
764
741
  def macro; :has_and_belongs_to_many; end
765
742
 
766
743
  def collection?
@@ -771,8 +748,7 @@ module ActiveRecord
771
748
  # Holds all the metadata about a :through association as it was specified
772
749
  # in the Active Record class.
773
750
  class ThroughReflection < AbstractReflection #:nodoc:
774
- attr_reader :delegate_reflection
775
- delegate :foreign_key, :foreign_type, :association_foreign_key,
751
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
776
752
  :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
777
753
 
778
754
  def initialize(delegate_reflection)
@@ -863,10 +839,6 @@ module ActiveRecord
863
839
  source_reflection.join_scopes(table, predicate_builder) + super
864
840
  end
865
841
 
866
- def source_type_scope
867
- through_reflection.klass.where(foreign_type => options[:source_type])
868
- end
869
-
870
842
  def has_scope?
871
843
  scope || options[:source_type] ||
872
844
  source_reflection.has_scope? ||
@@ -887,10 +859,6 @@ module ActiveRecord
887
859
  actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
888
860
  end
889
861
 
890
- def association_primary_key_type
891
- klass.type_for_attribute(association_primary_key.to_s)
892
- end
893
-
894
862
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
895
863
  #
896
864
  # class Post < ActiveRecord::Base
@@ -935,10 +903,6 @@ module ActiveRecord
935
903
  through_reflection.options
936
904
  end
937
905
 
938
- def join_id_for(owner) # :nodoc:
939
- source_reflection.join_id_for(owner)
940
- end
941
-
942
906
  def check_validity!
943
907
  if through_reflection.nil?
944
908
  raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
@@ -997,23 +961,23 @@ module ActiveRecord
997
961
  collect_join_reflections(seed + [self])
998
962
  end
999
963
 
1000
- def collect_join_reflections(seed)
1001
- a = source_reflection.add_as_source seed
1002
- if options[:source_type]
1003
- through_reflection.add_as_polymorphic_through self, a
1004
- else
1005
- through_reflection.add_as_through a
1006
- end
1007
- end
1008
-
1009
- private
964
+ # TODO Change this to private once we've dropped Ruby 2.2 support.
965
+ # Workaround for Ruby 2.2 "private attribute?" warning.
966
+ protected
967
+ attr_reader :delegate_reflection
1010
968
 
1011
969
  def actual_source_reflection # FIXME: this is a horrible name
1012
- source_reflection.send(:actual_source_reflection)
970
+ source_reflection.actual_source_reflection
1013
971
  end
1014
972
 
1015
- def primary_key(klass)
1016
- klass.primary_key || raise(UnknownPrimaryKey.new(klass))
973
+ private
974
+ def collect_join_reflections(seed)
975
+ a = source_reflection.add_as_source seed
976
+ if options[:source_type]
977
+ through_reflection.add_as_polymorphic_through self, a
978
+ else
979
+ through_reflection.add_as_through a
980
+ end
1017
981
  end
1018
982
 
1019
983
  def inverse_name; delegate_reflection.send(:inverse_name); end
@@ -1030,66 +994,32 @@ module ActiveRecord
1030
994
  end
1031
995
 
1032
996
  class PolymorphicReflection < AbstractReflection # :nodoc:
997
+ delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
998
+
1033
999
  def initialize(reflection, previous_reflection)
1034
1000
  @reflection = reflection
1035
1001
  @previous_reflection = previous_reflection
1036
1002
  end
1037
1003
 
1038
- def scopes
1039
- scopes = @previous_reflection.scopes
1040
- if @previous_reflection.options[:source_type]
1041
- scopes + [@previous_reflection.source_type_scope]
1042
- else
1043
- scopes
1044
- end
1045
- end
1046
-
1047
1004
  def join_scopes(table, predicate_builder) # :nodoc:
1048
1005
  scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1049
- if @previous_reflection.options[:source_type]
1050
- scopes + [@previous_reflection.source_type_scope]
1051
- else
1052
- scopes
1053
- end
1054
- end
1055
-
1056
- def klass
1057
- @reflection.klass
1058
- end
1059
-
1060
- def scope
1061
- @reflection.scope
1062
- end
1063
-
1064
- def table_name
1065
- @reflection.table_name
1066
- end
1067
-
1068
- def plural_name
1069
- @reflection.plural_name
1070
- end
1071
-
1072
- def type
1073
- @reflection.type
1006
+ scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
1074
1007
  end
1075
1008
 
1076
1009
  def constraints
1077
- @reflection.constraints + [source_type_info]
1078
- end
1079
-
1080
- def source_type_info
1081
- type = @previous_reflection.foreign_type
1082
- source_type = @previous_reflection.options[:source_type]
1083
- lambda { |object| where(type => source_type) }
1010
+ @reflection.constraints + [source_type_scope]
1084
1011
  end
1085
1012
 
1086
- def get_join_keys(association_klass)
1087
- @reflection.get_join_keys(association_klass)
1088
- end
1013
+ private
1014
+ def source_type_scope
1015
+ type = @previous_reflection.foreign_type
1016
+ source_type = @previous_reflection.options[:source_type]
1017
+ lambda { |object| where(type => source_type) }
1018
+ end
1089
1019
  end
1090
1020
 
1091
- class RuntimeReflection < PolymorphicReflection # :nodoc:
1092
- attr_accessor :next
1021
+ class RuntimeReflection < AbstractReflection # :nodoc:
1022
+ delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1093
1023
 
1094
1024
  def initialize(reflection, association)
1095
1025
  @reflection = reflection
@@ -1100,24 +1030,8 @@ module ActiveRecord
1100
1030
  @association.klass
1101
1031
  end
1102
1032
 
1103
- def table_name
1104
- klass.table_name
1105
- end
1106
-
1107
- def constraints
1108
- @reflection.constraints
1109
- end
1110
-
1111
- def source_type_info
1112
- @reflection.source_type_info
1113
- end
1114
-
1115
- def alias_candidate(name)
1116
- "#{plural_name}_#{name}_join"
1117
- end
1118
-
1119
- def alias_name
1120
- Arel::Table.new(table_name, type_caster: klass.type_caster)
1033
+ def aliased_table
1034
+ @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1121
1035
  end
1122
1036
 
1123
1037
  def all_includes; yield; end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Batches
3
5
  class BatchEnumerator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/relation/batches/batch_enumerator"
2
4
 
3
5
  module ActiveRecord
@@ -45,7 +47,12 @@ module ActiveRecord
45
47
  # handle from 10000 and beyond by setting the +:start+ and +:finish+
46
48
  # option on each worker.
47
49
  #
48
- # # Let's process from record 10_000 on.
50
+ # # In worker 1, let's process until 9999 records.
51
+ # Person.find_each(finish: 9_999) do |person|
52
+ # person.party_all_night!
53
+ # end
54
+ #
55
+ # # In worker 2, let's process from record 10_000 and onwards.
49
56
  # Person.find_each(start: 10_000) do |person|
50
57
  # person.party_all_night!
51
58
  # end
@@ -209,6 +216,7 @@ module ActiveRecord
209
216
 
210
217
  relation = relation.reorder(batch_order).limit(batch_limit)
211
218
  relation = apply_limits(relation, start, finish)
219
+ relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
212
220
  batch_relation = relation
213
221
 
214
222
  loop do
@@ -243,20 +251,27 @@ module ActiveRecord
243
251
  end
244
252
  end
245
253
 
246
- batch_relation = relation.where(arel_attribute(primary_key).gt(primary_key_offset))
254
+ attr = Relation::QueryAttribute.new(primary_key, primary_key_offset, klass.type_for_attribute(primary_key))
255
+ batch_relation = relation.where(arel_attribute(primary_key).gt(Arel::Nodes::BindParam.new(attr)))
247
256
  end
248
257
  end
249
258
 
250
259
  private
251
260
 
252
261
  def apply_limits(relation, start, finish)
253
- relation = relation.where(arel_attribute(primary_key).gteq(start)) if start
254
- relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish
262
+ if start
263
+ attr = Relation::QueryAttribute.new(primary_key, start, klass.type_for_attribute(primary_key))
264
+ relation = relation.where(arel_attribute(primary_key).gteq(Arel::Nodes::BindParam.new(attr)))
265
+ end
266
+ if finish
267
+ attr = Relation::QueryAttribute.new(primary_key, finish, klass.type_for_attribute(primary_key))
268
+ relation = relation.where(arel_attribute(primary_key).lteq(Arel::Nodes::BindParam.new(attr)))
269
+ end
255
270
  relation
256
271
  end
257
272
 
258
273
  def batch_order
259
- "#{quoted_table_name}.#{quoted_primary_key} ASC"
274
+ arel_attribute(primary_key).asc
260
275
  end
261
276
 
262
277
  def act_on_ignored_order(error_on_ignore)