activerecord 6.0.3 → 6.1.3

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 (246) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +968 -682
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record.rb +7 -14
  6. data/lib/active_record/aggregations.rb +5 -5
  7. data/lib/active_record/association_relation.rb +30 -12
  8. data/lib/active_record/associations.rb +118 -11
  9. data/lib/active_record/associations/alias_tracker.rb +19 -15
  10. data/lib/active_record/associations/association.rb +44 -28
  11. data/lib/active_record/associations/association_scope.rb +19 -15
  12. data/lib/active_record/associations/belongs_to_association.rb +22 -8
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  14. data/lib/active_record/associations/builder/association.rb +32 -5
  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 +39 -16
  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 +64 -54
  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 +11 -5
  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 +33 -8
  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 +152 -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 +191 -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 +66 -23
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
  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 +116 -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 +228 -83
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +54 -72
  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 +18 -3
  70. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -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 +5 -2
  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 +73 -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 +10 -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/money.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
  90. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  91. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  92. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  94. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  95. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  96. data/lib/active_record/connection_adapters/postgresql_adapter.rb +74 -63
  97. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  98. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  99. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +31 -6
  100. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  101. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  102. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
  103. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
  104. data/lib/active_record/connection_handling.rb +218 -71
  105. data/lib/active_record/core.rb +245 -61
  106. data/lib/active_record/database_configurations.rb +124 -85
  107. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  108. data/lib/active_record/database_configurations/database_config.rb +52 -9
  109. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  110. data/lib/active_record/database_configurations/url_config.rb +15 -40
  111. data/lib/active_record/delegated_type.rb +209 -0
  112. data/lib/active_record/destroy_association_async_job.rb +36 -0
  113. data/lib/active_record/enum.rb +82 -38
  114. data/lib/active_record/errors.rb +47 -12
  115. data/lib/active_record/explain.rb +9 -4
  116. data/lib/active_record/explain_subscriber.rb +1 -1
  117. data/lib/active_record/fixture_set/file.rb +10 -17
  118. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  119. data/lib/active_record/fixture_set/render_context.rb +1 -1
  120. data/lib/active_record/fixture_set/table_row.rb +2 -2
  121. data/lib/active_record/fixtures.rb +58 -9
  122. data/lib/active_record/gem_version.rb +1 -1
  123. data/lib/active_record/inheritance.rb +40 -18
  124. data/lib/active_record/insert_all.rb +35 -6
  125. data/lib/active_record/integration.rb +3 -5
  126. data/lib/active_record/internal_metadata.rb +16 -7
  127. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  128. data/lib/active_record/locking/optimistic.rb +33 -17
  129. data/lib/active_record/locking/pessimistic.rb +6 -2
  130. data/lib/active_record/log_subscriber.rb +27 -8
  131. data/lib/active_record/middleware/database_selector.rb +4 -1
  132. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  133. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  134. data/lib/active_record/migration.rb +114 -84
  135. data/lib/active_record/migration/command_recorder.rb +47 -27
  136. data/lib/active_record/migration/compatibility.rb +68 -17
  137. data/lib/active_record/model_schema.rb +117 -13
  138. data/lib/active_record/nested_attributes.rb +2 -3
  139. data/lib/active_record/no_touching.rb +1 -1
  140. data/lib/active_record/persistence.rb +50 -45
  141. data/lib/active_record/query_cache.rb +15 -5
  142. data/lib/active_record/querying.rb +11 -6
  143. data/lib/active_record/railtie.rb +64 -44
  144. data/lib/active_record/railties/console_sandbox.rb +2 -4
  145. data/lib/active_record/railties/databases.rake +276 -99
  146. data/lib/active_record/readonly_attributes.rb +4 -0
  147. data/lib/active_record/reflection.rb +71 -57
  148. data/lib/active_record/relation.rb +95 -67
  149. data/lib/active_record/relation/batches.rb +38 -31
  150. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  151. data/lib/active_record/relation/calculations.rb +101 -44
  152. data/lib/active_record/relation/delegation.rb +2 -1
  153. data/lib/active_record/relation/finder_methods.rb +45 -15
  154. data/lib/active_record/relation/from_clause.rb +1 -1
  155. data/lib/active_record/relation/merger.rb +27 -25
  156. data/lib/active_record/relation/predicate_builder.rb +61 -38
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  158. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  159. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  160. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  161. data/lib/active_record/relation/query_methods.rb +333 -195
  162. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  163. data/lib/active_record/relation/spawn_methods.rb +8 -7
  164. data/lib/active_record/relation/where_clause.rb +107 -60
  165. data/lib/active_record/result.rb +41 -33
  166. data/lib/active_record/runtime_registry.rb +2 -2
  167. data/lib/active_record/sanitization.rb +6 -17
  168. data/lib/active_record/schema_dumper.rb +34 -4
  169. data/lib/active_record/schema_migration.rb +2 -8
  170. data/lib/active_record/scoping/named.rb +6 -17
  171. data/lib/active_record/secure_token.rb +16 -8
  172. data/lib/active_record/serialization.rb +5 -3
  173. data/lib/active_record/signed_id.rb +116 -0
  174. data/lib/active_record/statement_cache.rb +20 -4
  175. data/lib/active_record/store.rb +2 -2
  176. data/lib/active_record/suppressor.rb +2 -2
  177. data/lib/active_record/table_metadata.rb +42 -51
  178. data/lib/active_record/tasks/database_tasks.rb +140 -113
  179. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  180. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  181. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  182. data/lib/active_record/test_databases.rb +5 -4
  183. data/lib/active_record/test_fixtures.rb +37 -16
  184. data/lib/active_record/timestamp.rb +4 -6
  185. data/lib/active_record/touch_later.rb +21 -21
  186. data/lib/active_record/transactions.rb +19 -66
  187. data/lib/active_record/type.rb +8 -1
  188. data/lib/active_record/type/serialized.rb +6 -2
  189. data/lib/active_record/type/time.rb +10 -0
  190. data/lib/active_record/type_caster/connection.rb +0 -1
  191. data/lib/active_record/type_caster/map.rb +8 -5
  192. data/lib/active_record/validations.rb +1 -0
  193. data/lib/active_record/validations/numericality.rb +35 -0
  194. data/lib/active_record/validations/uniqueness.rb +24 -4
  195. data/lib/arel.rb +5 -13
  196. data/lib/arel/attributes/attribute.rb +4 -0
  197. data/lib/arel/collectors/bind.rb +5 -0
  198. data/lib/arel/collectors/composite.rb +8 -0
  199. data/lib/arel/collectors/sql_string.rb +7 -0
  200. data/lib/arel/collectors/substitute_binds.rb +7 -0
  201. data/lib/arel/nodes.rb +3 -1
  202. data/lib/arel/nodes/binary.rb +82 -8
  203. data/lib/arel/nodes/bind_param.rb +8 -0
  204. data/lib/arel/nodes/casted.rb +21 -9
  205. data/lib/arel/nodes/equality.rb +6 -9
  206. data/lib/arel/nodes/grouping.rb +3 -0
  207. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  208. data/lib/arel/nodes/in.rb +8 -1
  209. data/lib/arel/nodes/infix_operation.rb +13 -1
  210. data/lib/arel/nodes/join_source.rb +1 -1
  211. data/lib/arel/nodes/node.rb +7 -6
  212. data/lib/arel/nodes/ordering.rb +27 -0
  213. data/lib/arel/nodes/sql_literal.rb +3 -0
  214. data/lib/arel/nodes/table_alias.rb +7 -3
  215. data/lib/arel/nodes/unary.rb +0 -1
  216. data/lib/arel/predications.rb +12 -18
  217. data/lib/arel/select_manager.rb +1 -2
  218. data/lib/arel/table.rb +13 -5
  219. data/lib/arel/visitors.rb +0 -7
  220. data/lib/arel/visitors/dot.rb +14 -2
  221. data/lib/arel/visitors/mysql.rb +11 -1
  222. data/lib/arel/visitors/postgresql.rb +15 -4
  223. data/lib/arel/visitors/to_sql.rb +89 -78
  224. data/lib/rails/generators/active_record/migration.rb +6 -1
  225. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  226. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  227. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  228. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  229. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  230. metadata +28 -29
  231. data/lib/active_record/advisory_lock_base.rb +0 -18
  232. data/lib/active_record/attribute_decorators.rb +0 -88
  233. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  234. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  235. data/lib/active_record/define_callbacks.rb +0 -22
  236. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  237. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  238. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  239. data/lib/arel/attributes.rb +0 -22
  240. data/lib/arel/visitors/depth_first.rb +0 -203
  241. data/lib/arel/visitors/ibm_db.rb +0 -34
  242. data/lib/arel/visitors/informix.rb +0 -62
  243. data/lib/arel/visitors/mssql.rb +0 -156
  244. data/lib/arel/visitors/oracle.rb +0 -158
  245. data/lib/arel/visitors/oracle12.rb +0 -65
  246. 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] || derive_class_name).to_s
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?
@@ -632,6 +623,7 @@ module ActiveRecord
632
623
  # with the current reflection's klass name.
633
624
  def valid_inverse_reflection?(reflection)
634
625
  reflection &&
626
+ foreign_key == reflection.foreign_key &&
635
627
  klass <= reflection.active_record &&
636
628
  can_find_inverse_of_automatically?(reflection)
637
629
  end
@@ -685,10 +677,6 @@ module ActiveRecord
685
677
  Associations::HasManyAssociation
686
678
  end
687
679
  end
688
-
689
- def association_primary_key(klass = nil)
690
- primary_key(klass || self.klass)
691
- end
692
680
  end
693
681
 
694
682
  class HasOneReflection < AssociationReflection # :nodoc:
@@ -723,6 +711,15 @@ module ActiveRecord
723
711
  end
724
712
  end
725
713
 
714
+ # klass option is necessary to support loading polymorphic associations
715
+ def association_primary_key(klass = nil)
716
+ if primary_key = options[:primary_key]
717
+ @association_primary_key ||= -primary_key.to_s
718
+ else
719
+ primary_key(klass || self.klass)
720
+ end
721
+ end
722
+
726
723
  def join_primary_key(klass = nil)
727
724
  polymorphic? ? association_primary_key(klass) : association_primary_key
728
725
  end
@@ -731,6 +728,10 @@ module ActiveRecord
731
728
  foreign_key
732
729
  end
733
730
 
731
+ def join_foreign_type
732
+ foreign_type
733
+ end
734
+
734
735
  private
735
736
  def can_find_inverse_of_automatically?(_)
736
737
  !polymorphic? && super
@@ -752,8 +753,8 @@ module ActiveRecord
752
753
  # Holds all the metadata about a :through association as it was specified
753
754
  # in the Active Record class.
754
755
  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
756
+ delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
757
+ :active_record_primary_key, :join_foreign_key, to: :source_reflection
757
758
 
758
759
  def initialize(delegate_reflection)
759
760
  @delegate_reflection = delegate_reflection
@@ -839,8 +840,8 @@ module ActiveRecord
839
840
  source_reflection.scopes + super
840
841
  end
841
842
 
842
- def join_scopes(table, predicate_builder) # :nodoc:
843
- source_reflection.join_scopes(table, predicate_builder) + super
843
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
844
+ source_reflection.join_scopes(table, predicate_builder, klass) + super
844
845
  end
845
846
 
846
847
  def has_scope?
@@ -860,7 +861,15 @@ module ActiveRecord
860
861
  def association_primary_key(klass = nil)
861
862
  # Get the "actual" source reflection if the immediate source reflection has a
862
863
  # source reflection itself
863
- actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass)
864
+ if primary_key = actual_source_reflection.options[:primary_key]
865
+ @association_primary_key ||= -primary_key.to_s
866
+ else
867
+ primary_key(klass || self.klass)
868
+ end
869
+ end
870
+
871
+ def join_primary_key(klass = self.klass)
872
+ source_reflection.join_primary_key(klass)
864
873
  end
865
874
 
866
875
  # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
@@ -909,7 +918,7 @@ module ActiveRecord
909
918
 
910
919
  def check_validity!
911
920
  if through_reflection.nil?
912
- raise HasManyThroughAssociationNotFoundError.new(active_record.name, self)
921
+ raise HasManyThroughAssociationNotFoundError.new(active_record, self)
913
922
  end
914
923
 
915
924
  if through_reflection.polymorphic?
@@ -996,16 +1005,17 @@ module ActiveRecord
996
1005
  end
997
1006
 
998
1007
  class PolymorphicReflection < AbstractReflection # :nodoc:
999
- delegate :klass, :scope, :plural_name, :type, :get_join_keys, :scope_for, to: :@reflection
1008
+ delegate :klass, :scope, :plural_name, :type, :join_primary_key, :join_foreign_key,
1009
+ :name, :scope_for, to: :@reflection
1000
1010
 
1001
1011
  def initialize(reflection, previous_reflection)
1002
1012
  @reflection = reflection
1003
1013
  @previous_reflection = previous_reflection
1004
1014
  end
1005
1015
 
1006
- def join_scopes(table, predicate_builder) # :nodoc:
1016
+ def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1007
1017
  scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1008
- scopes << build_scope(table, predicate_builder).instance_exec(nil, &source_type_scope)
1018
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1009
1019
  end
1010
1020
 
1011
1021
  def constraints
@@ -1021,7 +1031,7 @@ module ActiveRecord
1021
1031
  end
1022
1032
 
1023
1033
  class RuntimeReflection < AbstractReflection # :nodoc:
1024
- delegate :scope, :type, :constraints, :get_join_keys, to: :@reflection
1034
+ delegate :scope, :type, :constraints, :join_foreign_key, to: :@reflection
1025
1035
 
1026
1036
  def initialize(reflection, association)
1027
1037
  @reflection = reflection
@@ -1033,7 +1043,11 @@ module ActiveRecord
1033
1043
  end
1034
1044
 
1035
1045
  def aliased_table
1036
- @aliased_table ||= Arel::Table.new(table_name, type_caster: klass.type_caster)
1046
+ klass.arel_table
1047
+ end
1048
+
1049
+ def join_primary_key(klass = self.klass)
1050
+ @reflection.join_primary_key(klass)
1037
1051
  end
1038
1052
 
1039
1053
  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,9 @@ 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_clause.to_h(klass.table_name, equality_only: true)
687
+ create_with_value.each { |k, v| hash[k.to_s] = v } unless create_with_value.empty?
688
+ hash
675
689
  end
676
690
 
677
691
  # Returns true if relation needs eager loading.
@@ -715,7 +729,7 @@ module ActiveRecord
715
729
  end
716
730
 
717
731
  def inspect
718
- subject = loaded? ? records : self
732
+ subject = loaded? ? records : annotate("loading for inspect")
719
733
  entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
720
734
 
721
735
  entries[10] = "..." if entries.size == 11
@@ -732,25 +746,31 @@ module ActiveRecord
732
746
  end
733
747
 
734
748
  def alias_tracker(joins = [], aliases = nil) # :nodoc:
735
- joins += [aliases] if aliases
736
- ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins)
749
+ ActiveRecord::Associations::AliasTracker.create(connection, table.name, joins, aliases)
750
+ end
751
+
752
+ class StrictLoadingScope # :nodoc:
753
+ def self.empty_scope?
754
+ true
755
+ end
756
+
757
+ def self.strict_loading_value
758
+ true
759
+ end
737
760
  end
738
761
 
739
762
  def preload_associations(records) # :nodoc:
740
763
  preload = preload_values
741
764
  preload += includes_values unless eager_loading?
742
765
  preloader = nil
766
+ scope = strict_loading_value ? StrictLoadingScope : nil
743
767
  preload.each do |associations|
744
768
  preloader ||= build_preloader
745
- preloader.preload records, associations
769
+ preloader.preload records, associations, scope
746
770
  end
747
771
  end
748
772
 
749
- attr_reader :_deprecated_scope_source # :nodoc:
750
-
751
773
  protected
752
- attr_writer :_deprecated_scope_source # :nodoc:
753
-
754
774
  def load_records(records)
755
775
  @records = records.freeze
756
776
  @loaded = true
@@ -762,23 +782,29 @@ module ActiveRecord
762
782
 
763
783
  private
764
784
  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 }
785
+ @delegate_to_klass && klass.current_scope(true)
773
786
  end
774
787
 
775
- def _deprecated_scope_block(name, &block)
788
+ def current_scope_restoring_block(&block)
789
+ current_scope = klass.current_scope(true)
776
790
  -> record do
777
- klass.current_scope = _deprecated_spawn(name)
791
+ klass.current_scope = current_scope
778
792
  yield record if block_given?
779
793
  end
780
794
  end
781
795
 
796
+ def _new(attributes, &block)
797
+ klass.new(attributes, &block)
798
+ end
799
+
800
+ def _create(attributes, &block)
801
+ klass.create(attributes, &block)
802
+ end
803
+
804
+ def _create!(attributes, &block)
805
+ klass.create!(attributes, &block)
806
+ end
807
+
782
808
  def _scoping(scope)
783
809
  previous, klass.current_scope = klass.current_scope(true), scope
784
810
  yield
@@ -788,7 +814,7 @@ module ActiveRecord
788
814
 
789
815
  def _substitute_values(values)
790
816
  values.map do |name, value|
791
- attr = arel_attribute(name)
817
+ attr = table[name]
792
818
  unless Arel.arel_node?(value)
793
819
  type = klass.type_for_attribute(attr.name)
794
820
  value = predicate_builder.build_bind_attribute(attr.name, type.cast(value))
@@ -806,27 +832,29 @@ module ActiveRecord
806
832
 
807
833
  def exec_queries(&block)
808
834
  skip_query_cache_if_necessary do
809
- @records =
810
- if eager_loading?
835
+ records =
836
+ if where_clause.contradiction?
837
+ []
838
+ elsif eager_loading?
811
839
  apply_join_dependency do |relation, join_dependency|
812
840
  if relation.null_relation?
813
841
  []
814
842
  else
815
843
  relation = join_dependency.apply_column_aliases(relation)
816
844
  rows = connection.select_all(relation.arel, "SQL")
817
- join_dependency.instantiate(rows, &block)
845
+ join_dependency.instantiate(rows, strict_loading_value, &block)
818
846
  end.freeze
819
847
  end
820
848
  else
821
849
  klass.find_by_sql(arel, &block).freeze
822
850
  end
823
851
 
824
- preload_associations(@records) unless skip_preloading_value
852
+ preload_associations(records) unless skip_preloading_value
825
853
 
826
- @records.each(&:readonly!) if readonly_value
854
+ records.each(&:readonly!) if readonly_value
855
+ records.each(&:strict_loading!) if strict_loading_value
827
856
 
828
- @loaded = true
829
- @records
857
+ records
830
858
  end
831
859
  end
832
860
 
@@ -845,27 +873,27 @@ module ActiveRecord
845
873
  end
846
874
 
847
875
  def references_eager_loaded_tables?
848
- joined_tables = arel.join_sources.map do |join|
876
+ joined_tables = build_joins([]).flat_map do |join|
849
877
  if join.is_a?(Arel::Nodes::StringJoin)
850
878
  tables_in_string(join.left)
851
879
  else
852
- [join.left.table_name, join.left.table_alias]
880
+ join.left.name
853
881
  end
854
882
  end
855
883
 
856
- joined_tables += [table.name, table.table_alias]
884
+ joined_tables << table.name
857
885
 
858
886
  # 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
887
+ joined_tables.map!(&:downcase)
860
888
 
861
- (references_values - joined_tables).any?
889
+ !(references_values.map(&:to_s) - joined_tables).empty?
862
890
  end
863
891
 
864
892
  def tables_in_string(string)
865
893
  return [] if string.blank?
866
894
  # always convert table names to downcase as in Oracle quoted table names are in uppercase
867
895
  # 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_"]
896
+ string.scan(/[a-zA-Z_][.\w]+(?=.?\.)/).map!(&:downcase) - ["raw_sql_"]
869
897
  end
870
898
  end
871
899
  end