activerecord 6.0.3 → 6.1.0.rc1

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 (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +779 -705
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record.rb +7 -14
  6. data/lib/active_record/aggregations.rb +1 -1
  7. data/lib/active_record/association_relation.rb +22 -14
  8. data/lib/active_record/associations.rb +114 -11
  9. data/lib/active_record/associations/alias_tracker.rb +19 -15
  10. data/lib/active_record/associations/association.rb +40 -29
  11. data/lib/active_record/associations/association_scope.rb +17 -15
  12. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  14. data/lib/active_record/associations/builder/association.rb +9 -3
  15. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  18. data/lib/active_record/associations/builder/has_many.rb +6 -2
  19. data/lib/active_record/associations/builder/has_one.rb +11 -14
  20. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  21. data/lib/active_record/associations/collection_association.rb +19 -6
  22. data/lib/active_record/associations/collection_proxy.rb +13 -5
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +24 -2
  25. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  26. data/lib/active_record/associations/has_one_association.rb +15 -1
  27. data/lib/active_record/associations/join_dependency.rb +72 -50
  28. data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
  29. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  30. data/lib/active_record/associations/preloader.rb +11 -5
  31. data/lib/active_record/associations/preloader/association.rb +51 -25
  32. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  33. data/lib/active_record/associations/singular_association.rb +1 -1
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/attribute_assignment.rb +10 -8
  36. data/lib/active_record/attribute_methods.rb +52 -48
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  38. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  39. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  40. data/lib/active_record/attribute_methods/query.rb +3 -6
  41. data/lib/active_record/attribute_methods/read.rb +8 -11
  42. data/lib/active_record/attribute_methods/serialization.rb +4 -4
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  44. data/lib/active_record/attribute_methods/write.rb +12 -20
  45. data/lib/active_record/attributes.rb +27 -7
  46. data/lib/active_record/autosave_association.rb +57 -40
  47. data/lib/active_record/base.rb +2 -14
  48. data/lib/active_record/callbacks.rb +32 -22
  49. data/lib/active_record/coders/yaml_column.rb +1 -1
  50. data/lib/active_record/connection_adapters.rb +50 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +186 -134
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +112 -27
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +36 -69
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +129 -88
  64. data/lib/active_record/connection_adapters/column.rb +15 -1
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  67. data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -25
  68. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
  71. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  72. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  73. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +11 -7
  74. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  76. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  77. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +13 -54
  80. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  82. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
  89. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  90. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  91. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  93. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  94. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  96. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  97. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +31 -6
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  101. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
  103. data/lib/active_record/connection_handling.rb +210 -71
  104. data/lib/active_record/core.rb +220 -55
  105. data/lib/active_record/database_configurations.rb +124 -85
  106. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  107. data/lib/active_record/database_configurations/database_config.rb +52 -9
  108. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  109. data/lib/active_record/database_configurations/url_config.rb +15 -40
  110. data/lib/active_record/delegated_type.rb +209 -0
  111. data/lib/active_record/destroy_association_async_job.rb +36 -0
  112. data/lib/active_record/enum.rb +27 -10
  113. data/lib/active_record/errors.rb +47 -12
  114. data/lib/active_record/explain.rb +9 -4
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +10 -17
  117. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  118. data/lib/active_record/fixture_set/render_context.rb +1 -1
  119. data/lib/active_record/fixture_set/table_row.rb +2 -2
  120. data/lib/active_record/fixtures.rb +54 -8
  121. data/lib/active_record/gem_version.rb +3 -3
  122. data/lib/active_record/inheritance.rb +40 -18
  123. data/lib/active_record/insert_all.rb +33 -6
  124. data/lib/active_record/integration.rb +3 -5
  125. data/lib/active_record/internal_metadata.rb +15 -4
  126. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  127. data/lib/active_record/locking/optimistic.rb +22 -16
  128. data/lib/active_record/locking/pessimistic.rb +6 -2
  129. data/lib/active_record/log_subscriber.rb +26 -8
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/migration/command_recorder.rb +47 -27
  135. data/lib/active_record/migration/compatibility.rb +67 -17
  136. data/lib/active_record/model_schema.rb +88 -13
  137. data/lib/active_record/nested_attributes.rb +2 -3
  138. data/lib/active_record/no_touching.rb +1 -1
  139. data/lib/active_record/persistence.rb +50 -45
  140. data/lib/active_record/query_cache.rb +15 -5
  141. data/lib/active_record/querying.rb +11 -6
  142. data/lib/active_record/railtie.rb +64 -44
  143. data/lib/active_record/railties/databases.rake +253 -98
  144. data/lib/active_record/readonly_attributes.rb +4 -0
  145. data/lib/active_record/reflection.rb +70 -57
  146. data/lib/active_record/relation.rb +96 -67
  147. data/lib/active_record/relation/batches.rb +38 -31
  148. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  149. data/lib/active_record/relation/calculations.rb +101 -44
  150. data/lib/active_record/relation/delegation.rb +2 -1
  151. data/lib/active_record/relation/finder_methods.rb +45 -15
  152. data/lib/active_record/relation/from_clause.rb +1 -1
  153. data/lib/active_record/relation/merger.rb +27 -25
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  156. data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
  157. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  159. data/lib/active_record/relation/query_methods.rb +330 -195
  160. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  161. data/lib/active_record/relation/spawn_methods.rb +6 -5
  162. data/lib/active_record/relation/where_clause.rb +104 -57
  163. data/lib/active_record/result.rb +41 -33
  164. data/lib/active_record/runtime_registry.rb +2 -2
  165. data/lib/active_record/sanitization.rb +6 -17
  166. data/lib/active_record/schema_dumper.rb +34 -4
  167. data/lib/active_record/schema_migration.rb +0 -4
  168. data/lib/active_record/scoping/named.rb +6 -17
  169. data/lib/active_record/secure_token.rb +16 -8
  170. data/lib/active_record/serialization.rb +5 -3
  171. data/lib/active_record/signed_id.rb +116 -0
  172. data/lib/active_record/statement_cache.rb +20 -4
  173. data/lib/active_record/store.rb +2 -2
  174. data/lib/active_record/suppressor.rb +2 -2
  175. data/lib/active_record/table_metadata.rb +36 -52
  176. data/lib/active_record/tasks/database_tasks.rb +139 -113
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  180. data/lib/active_record/test_databases.rb +5 -4
  181. data/lib/active_record/test_fixtures.rb +37 -16
  182. data/lib/active_record/timestamp.rb +4 -6
  183. data/lib/active_record/touch_later.rb +21 -21
  184. data/lib/active_record/transactions.rb +15 -64
  185. data/lib/active_record/type.rb +8 -1
  186. data/lib/active_record/type/serialized.rb +6 -2
  187. data/lib/active_record/type/time.rb +10 -0
  188. data/lib/active_record/type_caster/connection.rb +0 -1
  189. data/lib/active_record/type_caster/map.rb +8 -5
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record/validations/numericality.rb +35 -0
  192. data/lib/active_record/validations/uniqueness.rb +24 -4
  193. data/lib/arel.rb +5 -13
  194. data/lib/arel/attributes/attribute.rb +4 -0
  195. data/lib/arel/collectors/bind.rb +5 -0
  196. data/lib/arel/collectors/composite.rb +8 -0
  197. data/lib/arel/collectors/sql_string.rb +7 -0
  198. data/lib/arel/collectors/substitute_binds.rb +7 -0
  199. data/lib/arel/nodes.rb +3 -1
  200. data/lib/arel/nodes/binary.rb +82 -8
  201. data/lib/arel/nodes/bind_param.rb +8 -0
  202. data/lib/arel/nodes/casted.rb +21 -9
  203. data/lib/arel/nodes/equality.rb +6 -9
  204. data/lib/arel/nodes/grouping.rb +3 -0
  205. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  206. data/lib/arel/nodes/in.rb +8 -1
  207. data/lib/arel/nodes/infix_operation.rb +13 -1
  208. data/lib/arel/nodes/join_source.rb +1 -1
  209. data/lib/arel/nodes/node.rb +7 -6
  210. data/lib/arel/nodes/ordering.rb +27 -0
  211. data/lib/arel/nodes/sql_literal.rb +3 -0
  212. data/lib/arel/nodes/table_alias.rb +7 -3
  213. data/lib/arel/nodes/unary.rb +0 -1
  214. data/lib/arel/predications.rb +12 -18
  215. data/lib/arel/select_manager.rb +1 -2
  216. data/lib/arel/table.rb +13 -5
  217. data/lib/arel/visitors.rb +0 -7
  218. data/lib/arel/visitors/dot.rb +14 -2
  219. data/lib/arel/visitors/mysql.rb +11 -1
  220. data/lib/arel/visitors/postgresql.rb +15 -4
  221. data/lib/arel/visitors/to_sql.rb +89 -78
  222. data/lib/rails/generators/active_record/migration.rb +6 -1
  223. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  224. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  225. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  226. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  227. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  228. metadata +27 -28
  229. data/lib/active_record/advisory_lock_base.rb +0 -18
  230. data/lib/active_record/attribute_decorators.rb +0 -88
  231. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  232. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  233. data/lib/active_record/define_callbacks.rb +0 -22
  234. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  235. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  236. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  237. data/lib/arel/attributes.rb +0 -22
  238. data/lib/arel/visitors/depth_first.rb +0 -203
  239. data/lib/arel/visitors/ibm_db.rb +0 -34
  240. data/lib/arel/visitors/informix.rb +0 -62
  241. data/lib/arel/visitors/mssql.rb +0 -156
  242. data/lib/arel/visitors/oracle.rb +0 -158
  243. data/lib/arel/visitors/oracle12.rb +0 -65
  244. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -19,6 +19,10 @@ module ActiveRecord
19
19
  def readonly_attributes
20
20
  _attr_readonly
21
21
  end
22
+
23
+ def readonly_attribute?(name) # :nodoc:
24
+ _attr_readonly.include?(name)
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/string/filters"
4
- require "concurrent/map"
5
4
 
6
5
  module ActiveRecord
7
6
  # = Active Record Reflection
@@ -163,13 +162,7 @@ module ActiveRecord
163
162
  # <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>'Money'</tt>
164
163
  # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
165
164
  def class_name
166
- @class_name ||= (options[:class_name] || derive_class_name).to_s
167
- end
168
-
169
- JoinKeys = Struct.new(:key, :foreign_key) # :nodoc:
170
-
171
- def join_keys
172
- @join_keys ||= get_join_keys(klass)
165
+ @class_name ||= -(options[:class_name]&.to_s || derive_class_name)
173
166
  end
174
167
 
175
168
  # Returns a list of scopes that should be applied for this Reflection
@@ -189,10 +182,10 @@ module ActiveRecord
189
182
 
190
183
  scope_chain_items.inject(klass_scope, &:merge!)
191
184
 
192
- key = join_keys.key
193
- foreign_key = join_keys.foreign_key
185
+ primary_key = join_primary_key
186
+ foreign_key = join_foreign_key
194
187
 
195
- klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
188
+ klass_scope.where!(table[primary_key].eq(foreign_table[foreign_key]))
196
189
 
197
190
  if klass.finder_needs_type_condition?
198
191
  klass_scope.where!(klass.send(:type_condition, table))
@@ -201,9 +194,9 @@ module ActiveRecord
201
194
  klass_scope
202
195
  end
203
196
 
204
- def join_scopes(table, predicate_builder) # :nodoc:
197
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
205
198
  if scope
206
- [scope_for(build_scope(table, predicate_builder))]
199
+ [scope_for(build_scope(table, predicate_builder, klass))]
207
200
  else
208
201
  []
209
202
  end
@@ -219,14 +212,14 @@ module ActiveRecord
219
212
  end
220
213
 
221
214
  def counter_cache_column
222
- if belongs_to?
215
+ @counter_cache_column ||= if belongs_to?
223
216
  if options[:counter_cache] == true
224
- "#{active_record.name.demodulize.underscore.pluralize}_count"
217
+ -"#{active_record.name.demodulize.underscore.pluralize}_count"
225
218
  elsif options[:counter_cache]
226
- options[:counter_cache].to_s
219
+ -options[:counter_cache].to_s
227
220
  end
228
221
  else
229
- options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count"
222
+ -(options[:counter_cache]&.to_s || "#{name}_count")
230
223
  end
231
224
  end
232
225
 
@@ -273,7 +266,7 @@ module ActiveRecord
273
266
  def has_cached_counter?
274
267
  options[:counter_cache] ||
275
268
  inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] &&
276
- !!active_record.columns_hash[counter_cache_column]
269
+ active_record.has_attribute?(counter_cache_column)
277
270
  end
278
271
 
279
272
  def counter_must_be_updated_by_has_many?
@@ -288,11 +281,7 @@ module ActiveRecord
288
281
  collect_join_chain
289
282
  end
290
283
 
291
- def get_join_keys(association_klass)
292
- JoinKeys.new(join_primary_key(association_klass), join_foreign_key)
293
- end
294
-
295
- def build_scope(table, predicate_builder = predicate_builder(table))
284
+ def build_scope(table, predicate_builder = predicate_builder(table), klass = self.klass)
296
285
  Relation.create(
297
286
  klass,
298
287
  table: table,
@@ -300,12 +289,8 @@ module ActiveRecord
300
289
  )
301
290
  end
302
291
 
303
- def join_primary_key(*)
304
- foreign_key
305
- end
306
-
307
- def join_foreign_key
308
- active_record_primary_key
292
+ def strict_loading?
293
+ options[:strict_loading]
309
294
  end
310
295
 
311
296
  protected
@@ -429,22 +414,21 @@ module ActiveRecord
429
414
 
430
415
  def initialize(name, scope, options, active_record)
431
416
  super
432
- @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type")
433
- @foreign_type = options[:polymorphic] && (options[:foreign_type] || "#{name}_type")
417
+ @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
+ @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
434
419
  @constructable = calculate_constructable(macro, options)
435
- @association_scope_cache = Concurrent::Map.new
436
420
 
437
421
  if options[:class_name] && options[:class_name].class == Class
438
422
  raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
439
423
  end
440
424
  end
441
425
 
442
- def association_scope_cache(conn, owner, &block)
443
- key = conn.prepared_statements
426
+ def association_scope_cache(klass, owner, &block)
427
+ key = self
444
428
  if polymorphic?
445
429
  key = [key, owner._read_attribute(@foreign_type)]
446
430
  end
447
- @association_scope_cache.compute_if_absent(key) { StatementCache.create(conn, &block) }
431
+ klass.cached_find_by_statement(key, &block)
448
432
  end
449
433
 
450
434
  def constructable? # :nodoc:
@@ -452,24 +436,31 @@ module ActiveRecord
452
436
  end
453
437
 
454
438
  def join_table
455
- @join_table ||= options[:join_table] || derive_join_table
439
+ @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
456
440
  end
457
441
 
458
442
  def foreign_key
459
- @foreign_key ||= options[:foreign_key] || derive_foreign_key.freeze
443
+ @foreign_key ||= -(options[:foreign_key]&.to_s || derive_foreign_key)
460
444
  end
461
445
 
462
446
  def association_foreign_key
463
- @association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
447
+ @association_foreign_key ||= -(options[:association_foreign_key]&.to_s || class_name.foreign_key)
464
448
  end
465
449
 
466
- # klass option is necessary to support loading polymorphic associations
467
450
  def association_primary_key(klass = nil)
468
- options[:primary_key] || primary_key(klass || self.klass)
451
+ primary_key(klass || self.klass)
469
452
  end
470
453
 
471
454
  def active_record_primary_key
472
- @active_record_primary_key ||= options[:primary_key] || primary_key(active_record)
455
+ @active_record_primary_key ||= -(options[:primary_key]&.to_s || primary_key(active_record))
456
+ end
457
+
458
+ def join_primary_key(klass = nil)
459
+ foreign_key
460
+ end
461
+
462
+ def join_foreign_key
463
+ active_record_primary_key
473
464
  end
474
465
 
475
466
  def check_validity!
@@ -510,7 +501,7 @@ module ActiveRecord
510
501
  # This is for clearing cache on the reflection. Useful for tests that need to compare
511
502
  # SQL queries on associations.
512
503
  def clear_association_scope_cache # :nodoc:
513
- @association_scope_cache.clear
504
+ klass.initialize_find_by_cache
514
505
  end
515
506
 
516
507
  def nested?
@@ -685,10 +676,6 @@ module ActiveRecord
685
676
  Associations::HasManyAssociation
686
677
  end
687
678
  end
688
-
689
- def association_primary_key(klass = nil)
690
- primary_key(klass || self.klass)
691
- end
692
679
  end
693
680
 
694
681
  class HasOneReflection < AssociationReflection # :nodoc:
@@ -723,6 +710,15 @@ module ActiveRecord
723
710
  end
724
711
  end
725
712
 
713
+ # klass option is necessary to support loading polymorphic associations
714
+ def association_primary_key(klass = nil)
715
+ if primary_key = options[:primary_key]
716
+ @association_primary_key ||= -primary_key.to_s
717
+ else
718
+ primary_key(klass || self.klass)
719
+ end
720
+ end
721
+
726
722
  def join_primary_key(klass = nil)
727
723
  polymorphic? ? association_primary_key(klass) : association_primary_key
728
724
  end
@@ -731,6 +727,10 @@ module ActiveRecord
731
727
  foreign_key
732
728
  end
733
729
 
730
+ def join_foreign_type
731
+ foreign_type
732
+ end
733
+
734
734
  private
735
735
  def can_find_inverse_of_automatically?(_)
736
736
  !polymorphic? && super
@@ -752,8 +752,8 @@ module ActiveRecord
752
752
  # Holds all the metadata about a :through association as it was specified
753
753
  # in the Active Record class.
754
754
  class ThroughReflection < AbstractReflection #:nodoc:
755
- delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for,
756
- :active_record_primary_key, :type, :get_join_keys, to: :source_reflection
755
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
756
+ :active_record_primary_key, :join_foreign_key, to: :source_reflection
757
757
 
758
758
  def initialize(delegate_reflection)
759
759
  @delegate_reflection = delegate_reflection
@@ -839,8 +839,8 @@ module ActiveRecord
839
839
  source_reflection.scopes + super
840
840
  end
841
841
 
842
- def join_scopes(table, predicate_builder) # :nodoc:
843
- source_reflection.join_scopes(table, predicate_builder) + super
842
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
843
+ source_reflection.join_scopes(table, predicate_builder, klass) + super
844
844
  end
845
845
 
846
846
  def has_scope?
@@ -860,7 +860,15 @@ module ActiveRecord
860
860
  def association_primary_key(klass = nil)
861
861
  # Get the "actual" source reflection if the immediate source reflection has a
862
862
  # source reflection itself
863
- actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
863
+ if primary_key = actual_source_reflection.options[:primary_key]
864
+ @association_primary_key ||= -primary_key.to_s
865
+ else
866
+ primary_key(klass || self.klass)
867
+ end
868
+ end
869
+
870
+ def join_primary_key(klass = self.klass)
871
+ source_reflection.join_primary_key(klass)
864
872
  end
865
873
 
866
874
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
@@ -909,7 +917,7 @@ module ActiveRecord
909
917
 
910
918
  def check_validity!
911
919
  if through_reflection.nil?
912
- raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
920
+ raise HasManyThroughAssociationNotFoundError.new(active_record, self)
913
921
  end
914
922
 
915
923
  if through_reflection.polymorphic?
@@ -996,16 +1004,17 @@ module ActiveRecord
996
1004
  end
997
1005
 
998
1006
  class PolymorphicReflection < AbstractReflection # :nodoc:
999
- delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
1007
+ delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
1008
+ :name, :scope_for, to: :@reflection
1000
1009
 
1001
1010
  def initialize(reflection, previous_reflection)
1002
1011
  @reflection = reflection
1003
1012
  @previous_reflection = previous_reflection
1004
1013
  end
1005
1014
 
1006
- def join_scopes(table, predicate_builder) # :nodoc:
1015
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1007
1016
  scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1008
- scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
1017
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1009
1018
  end
1010
1019
 
1011
1020
  def constraints
@@ -1021,7 +1030,7 @@ module ActiveRecord
1021
1030
  end
1022
1031
 
1023
1032
  class RuntimeReflection < AbstractReflection # :nodoc:
1024
- delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1033
+ delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
1025
1034
 
1026
1035
  def initialize(reflection, association)
1027
1036
  @reflection = reflection
@@ -1033,7 +1042,11 @@ module ActiveRecord
1033
1042
  end
1034
1043
 
1035
1044
  def aliased_table
1036
- @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1045
+ klass.arel_table
1046
+ end
1047
+
1048
+ def join_primary_key(klass = self.klass)
1049
+ @reflection.join_primary_key(klass)
1037
1050
  end
1038
1051
 
1039
1052
  def all_includes; yield; end
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  :order, :joins, :left_outer_joins, :references,
8
8
  :extending, :unscope, :optimizer_hints, :annotate]
9
9
 
10
- SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
10
+ SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering, :strict_loading,
11
11
  :reverse_order, :distinct, :create_with, :skip_query_cache]
12
12
 
13
13
  CLAUSE_METHODS = [:where, :having, :from]
@@ -28,7 +28,6 @@ module ActiveRecord
28
28
  @klass = klass
29
29
  @table = table
30
30
  @values = values
31
- @offsets = {}
32
31
  @loaded = false
33
32
  @predicate_builder = predicate_builder
34
33
  @delegate_to_klass = false
@@ -40,8 +39,9 @@ module ActiveRecord
40
39
  end
41
40
 
42
41
  def arel_attribute(name) # :nodoc:
43
- klass.arel_attribute(name, table)
42
+ table[name]
44
43
  end
44
+ deprecate :arel_attribute
45
45
 
46
46
  def bind_attribute(name, value) # :nodoc:
47
47
  if reflection = klass._reflect_on_association(name)
@@ -49,7 +49,7 @@ module ActiveRecord
49
49
  value = value.read_attribute(reflection.klass.primary_key) unless value.nil?
50
50
  end
51
51
 
52
- attr = arel_attribute(name)
52
+ attr = table[name]
53
53
  bind = predicate_builder.build_bind_attribute(attr.name, value)
54
54
  yield attr, bind
55
55
  end
@@ -67,10 +67,9 @@ module ActiveRecord
67
67
  # user = users.new { |user| user.name = 'Oscar' }
68
68
  # user.name # => Oscar
69
69
  def new(attributes = nil, &block)
70
- block = _deprecated_scope_block("new", &block)
71
- scoping { klass.new(attributes, &block) }
70
+ block = current_scope_restoring_block(&block)
71
+ scoping { _new(attributes, &block) }
72
72
  end
73
-
74
73
  alias build new
75
74
 
76
75
  # Tries to create a new record with the same scoped attributes
@@ -96,8 +95,8 @@ module ActiveRecord
96
95
  if attributes.is_a?(Array)
97
96
  attributes.collect { |attr| create(attr, &block) }
98
97
  else
99
- block = _deprecated_scope_block("create", &block)
100
- scoping { klass.create(attributes, &block) }
98
+ block = current_scope_restoring_block(&block)
99
+ scoping { _create(attributes, &block) }
101
100
  end
102
101
  end
103
102
 
@@ -111,8 +110,8 @@ module ActiveRecord
111
110
  if attributes.is_a?(Array)
112
111
  attributes.collect { |attr| create!(attr, &block) }
113
112
  else
114
- block = _deprecated_scope_block("create!", &block)
115
- scoping { klass.create!(attributes, &block) }
113
+ block = current_scope_restoring_block(&block)
114
+ scoping { _create!(attributes, &block) }
116
115
  end
117
116
  end
118
117
 
@@ -308,7 +307,7 @@ module ActiveRecord
308
307
  # last updated record.
309
308
  #
310
309
  # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
311
- def cache_key(timestamp_column = :updated_at)
310
+ def cache_key(timestamp_column = "updated_at")
312
311
  @cache_keys ||= {}
313
312
  @cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
314
313
  end
@@ -317,7 +316,7 @@ module ActiveRecord
317
316
  query_signature = ActiveSupport::Digest.hexdigest(to_sql)
318
317
  key = "#{klass.model_name.cache_key}/query-#{query_signature}"
319
318
 
320
- if cache_version(timestamp_column)
319
+ if collection_cache_versioning
321
320
  key
322
321
  else
323
322
  "#{key}-#{compute_cache_version(timestamp_column)}"
@@ -343,15 +342,17 @@ module ActiveRecord
343
342
  end
344
343
 
345
344
  def compute_cache_version(timestamp_column) # :nodoc:
345
+ timestamp_column = timestamp_column.to_s
346
+
346
347
  if loaded? || distinct_value
347
348
  size = records.size
348
349
  if size > 0
349
- timestamp = max_by(&timestamp_column)._read_attribute(timestamp_column)
350
+ timestamp = records.map { |record| record.read_attribute(timestamp_column) }.max
350
351
  end
351
352
  else
352
353
  collection = eager_loading? ? apply_join_dependency : self
353
354
 
354
- column = connection.visitor.compile(arel_attribute(timestamp_column))
355
+ column = connection.visitor.compile(table[timestamp_column])
355
356
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
356
357
 
357
358
  if collection.has_limit_or_offset?
@@ -365,14 +366,12 @@ module ActiveRecord
365
366
  arel = query.arel
366
367
  end
367
368
 
368
- result = connection.select_one(arel, nil)
369
+ size, timestamp = connection.select_rows(arel, nil).first
369
370
 
370
- if result
371
+ if size
371
372
  column_type = klass.type_for_attribute(timestamp_column)
372
- timestamp = column_type.deserialize(result["timestamp"])
373
- size = result["size"]
373
+ timestamp = column_type.deserialize(timestamp)
374
374
  else
375
- timestamp = nil
376
375
  size = 0
377
376
  end
378
377
  end
@@ -407,9 +406,9 @@ module ActiveRecord
407
406
  already_in_scope? ? yield : _scoping(self) { yield }
408
407
  end
409
408
 
410
- def _exec_scope(name, *args, &block) # :nodoc:
409
+ def _exec_scope(*args, &block) # :nodoc:
411
410
  @delegate_to_klass = true
412
- _scoping(_deprecated_spawn(name)) { instance_exec(*args, &block) || self }
411
+ _scoping(nil) { instance_exec(*args, &block) || self }
413
412
  ensure
414
413
  @delegate_to_klass = false
415
414
  end
@@ -417,7 +416,7 @@ module ActiveRecord
417
416
  # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE
418
417
  # statement and sends it straight to the database. It does not instantiate the involved models and it does not
419
418
  # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
420
- # Active Record's normal type casting and serialization.
419
+ # Active Record's normal type casting and serialization. Returns the number of rows affected.
421
420
  #
422
421
  # Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
423
422
  #
@@ -448,7 +447,7 @@ module ActiveRecord
448
447
 
449
448
  stmt = Arel::UpdateManager.new
450
449
  stmt.table(arel.join_sources.empty? ? table : arel.source)
451
- stmt.key = arel_attribute(primary_key)
450
+ stmt.key = table[primary_key]
452
451
  stmt.take(arel.limit)
453
452
  stmt.offset(arel.offset)
454
453
  stmt.order(*arel.orders)
@@ -458,7 +457,7 @@ module ActiveRecord
458
457
  if klass.locking_enabled? &&
459
458
  !updates.key?(klass.locking_column) &&
460
459
  !updates.key?(klass.locking_column.to_sym)
461
- attr = arel_attribute(klass.locking_column)
460
+ attr = table[klass.locking_column]
462
461
  updates[attr.name] = _increment_attribute(attr)
463
462
  end
464
463
  stmt.set _substitute_values(updates)
@@ -477,12 +476,24 @@ module ActiveRecord
477
476
  end
478
477
  end
479
478
 
480
- def update_counters(counters) # :nodoc:
479
+ # Updates the counters of the records in the current relation.
480
+ #
481
+ # ==== Parameters
482
+ #
483
+ # * +counter+ - A Hash containing the names of the fields to update as keys and the amount to update as values.
484
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
485
+ # * If attributes names are passed, they are updated along with update_at/on attributes.
486
+ #
487
+ # ==== Examples
488
+ #
489
+ # # For Posts by a given author increment the comment_count by 1.
490
+ # Post.where(author_id: author.id).update_counters(comment_count: 1)
491
+ def update_counters(counters)
481
492
  touch = counters.delete(:touch)
482
493
 
483
494
  updates = {}
484
495
  counters.each do |counter_name, value|
485
- attr = arel_attribute(counter_name)
496
+ attr = table[counter_name]
486
497
  updates[attr.name] = _increment_attribute(attr, value)
487
498
  end
488
499
 
@@ -497,8 +508,8 @@ module ActiveRecord
497
508
  update_all updates
498
509
  end
499
510
 
500
- # Touches all records in the current relation without instantiating records first with the +updated_at+/+updated_on+ attributes
501
- # set to the current time or the time specified.
511
+ # Touches all records in the current relation, setting the +updated_at+/+updated_on+ attributes to the current time or the time specified.
512
+ # It does not instantiate the involved models, and it does not trigger Active Record callbacks or validations.
502
513
  # This method can be passed attribute names and an optional time argument.
503
514
  # If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
504
515
  # If no time argument is passed, the current time is used as default.
@@ -578,7 +589,7 @@ module ActiveRecord
578
589
 
579
590
  stmt = Arel::DeleteManager.new
580
591
  stmt.from(arel.join_sources.empty? ? table : arel.source)
581
- stmt.key = arel_attribute(primary_key)
592
+ stmt.key = table[primary_key]
582
593
  stmt.take(arel.limit)
583
594
  stmt.offset(arel.offset)
584
595
  stmt.order(*arel.orders)
@@ -623,7 +634,10 @@ module ActiveRecord
623
634
  #
624
635
  # Post.where(published: true).load # => #<ActiveRecord::Relation>
625
636
  def load(&block)
626
- exec_queries(&block) unless loaded?
637
+ unless loaded?
638
+ @records = exec_queries(&block)
639
+ @loaded = true
640
+ end
627
641
 
628
642
  self
629
643
  end
@@ -636,11 +650,9 @@ module ActiveRecord
636
650
 
637
651
  def reset
638
652
  @delegate_to_klass = false
639
- @_deprecated_scope_source = nil
640
653
  @to_sql = @arel = @loaded = @should_eager_load = nil
654
+ @offsets = @take = nil
641
655
  @records = [].freeze
642
- @offsets = {}
643
- @take = nil
644
656
  self
645
657
  end
646
658
 
@@ -671,7 +683,10 @@ module ActiveRecord
671
683
  end
672
684
 
673
685
  def scope_for_create
674
- where_values_hash.merge!(create_with_value.stringify_keys)
686
+ hash = where_values_hash
687
+ hash.delete(klass.inheritance_column) if klass.finder_needs_type_condition?
688
+ create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
689
+ hash
675
690
  end
676
691
 
677
692
  # Returns true if relation needs eager loading.
@@ -715,7 +730,7 @@ module ActiveRecord
715
730
  end
716
731
 
717
732
  def inspect
718
- subject = loaded? ? records : self
733
+ subject = loaded? ? records : annotate("loading for inspect")
719
734
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
720
735
 
721
736
  entries[10] = "..." if entries.size == 11
@@ -732,25 +747,31 @@ module ActiveRecord
732
747
  end
733
748
 
734
749
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
735
- joins += [aliases] if aliases
736
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
750
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
751
+ end
752
+
753
+ class StrictLoadingScope # :nodoc:
754
+ def self.empty_scope?
755
+ true
756
+ end
757
+
758
+ def self.strict_loading_value
759
+ true
760
+ end
737
761
  end
738
762
 
739
763
  def preload_associations(records) # :nodoc:
740
764
  preload = preload_values
741
765
  preload += includes_values unless eager_loading?
742
766
  preloader = nil
767
+ scope = strict_loading_value ? StrictLoadingScope : nil
743
768
  preload.each do |associations|
744
769
  preloader ||= build_preloader
745
- preloader.preload records, associations
770
+ preloader.preload records, associations, scope
746
771
  end
747
772
  end
748
773
 
749
- attr_reader :_deprecated_scope_source # :nodoc:
750
-
751
774
  protected
752
- attr_writer :_deprecated_scope_source # :nodoc:
753
-
754
775
  def load_records(records)
755
776
  @records = records.freeze
756
777
  @loaded = true
@@ -762,23 +783,29 @@ module ActiveRecord
762
783
 
763
784
  private
764
785
  def already_in_scope?
765
- @delegate_to_klass && begin
766
- scope = klass.current_scope(true)
767
- scope && !scope._deprecated_scope_source
768
- end
769
- end
770
-
771
- def _deprecated_spawn(name)
772
- spawn.tap { |scope| scope._deprecated_scope_source = name }
786
+ @delegate_to_klass && klass.current_scope(true)
773
787
  end
774
788
 
775
- def _deprecated_scope_block(name, &block)
789
+ def current_scope_restoring_block(&block)
790
+ current_scope = klass.current_scope(true)
776
791
  -> record do
777
- klass.current_scope = _deprecated_spawn(name)
792
+ klass.current_scope = current_scope
778
793
  yield record if block_given?
779
794
  end
780
795
  end
781
796
 
797
+ def _new(attributes, &block)
798
+ klass.new(attributes, &block)
799
+ end
800
+
801
+ def _create(attributes, &block)
802
+ klass.create(attributes, &block)
803
+ end
804
+
805
+ def _create!(attributes, &block)
806
+ klass.create!(attributes, &block)
807
+ end
808
+
782
809
  def _scoping(scope)
783
810
  previous, klass.current_scope = klass.current_scope(true), scope
784
811
  yield
@@ -788,7 +815,7 @@ module ActiveRecord
788
815
 
789
816
  def _substitute_values(values)
790
817
  values.map do |name, value|
791
- attr = arel_attribute(name)
818
+ attr = table[name]
792
819
  unless Arel.arel_node?(value)
793
820
  type = klass.type_for_attribute(attr.name)
794
821
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
@@ -806,27 +833,29 @@ module ActiveRecord
806
833
 
807
834
  def exec_queries(&block)
808
835
  skip_query_cache_if_necessary do
809
- @records =
810
- if eager_loading?
836
+ records =
837
+ if where_clause.contradiction?
838
+ []
839
+ elsif eager_loading?
811
840
  apply_join_dependency do |relation, join_dependency|
812
841
  if relation.null_relation?
813
842
  []
814
843
  else
815
844
  relation = join_dependency.apply_column_aliases(relation)
816
845
  rows = connection.select_all(relation.arel, "SQL")
817
- join_dependency.instantiate(rows, &block)
846
+ join_dependency.instantiate(rows, strict_loading_value, &block)
818
847
  end.freeze
819
848
  end
820
849
  else
821
850
  klass.find_by_sql(arel, &block).freeze
822
851
  end
823
852
 
824
- preload_associations(@records) unless skip_preloading_value
853
+ preload_associations(records) unless skip_preloading_value
825
854
 
826
- @records.each(&:readonly!) if readonly_value
855
+ records.each(&:readonly!) if readonly_value
856
+ records.each(&:strict_loading!) if strict_loading_value
827
857
 
828
- @loaded = true
829
- @records
858
+ records
830
859
  end
831
860
  end
832
861
 
@@ -845,27 +874,27 @@ module ActiveRecord
845
874
  end
846
875
 
847
876
  def references_eager_loaded_tables?
848
- joined_tables = arel.join_sources.map do |join|
877
+ joined_tables = build_joins([]).flat_map do |join|
849
878
  if join.is_a?(Arel::Nodes::StringJoin)
850
879
  tables_in_string(join.left)
851
880
  else
852
- [join.left.table_name, join.left.table_alias]
881
+ join.left.name
853
882
  end
854
883
  end
855
884
 
856
- joined_tables += [table.name, table.table_alias]
885
+ joined_tables << table.name
857
886
 
858
887
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
859
- joined_tables = joined_tables.flatten.compact.map(&:downcase).uniq
888
+ joined_tables.map!(&:downcase)
860
889
 
861
- (references_values - joined_tables).any?
890
+ !(references_values.map(&:to_s) - joined_tables).empty?
862
891
  end
863
892
 
864
893
  def tables_in_string(string)
865
894
  return [] if string.blank?
866
895
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
867
896
  # ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
868
- string.scan(/([a-zA-Z_][.\w]+).?\./).flatten.map(&:downcase).uniq - ["raw_sql_"]
897
+ string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
869
898
  end
870
899
  end
871
900
  end