activerecord 5.1.5 → 5.2.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 +450 -699
  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 +4 -2
  9. data/lib/active_record/associations/alias_tracker.rb +19 -27
  10. data/lib/active_record/associations/association.rb +33 -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 +1 -1
  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 +52 -41
  22. data/lib/active_record/associations/collection_proxy.rb +12 -15
  23. data/lib/active_record/associations/foreign_association.rb +2 -0
  24. data/lib/active_record/associations/has_many_association.rb +3 -1
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -19
  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 +22 -67
  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 +17 -37
  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 +25 -214
  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 +16 -14
  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 +2 -0
  55. data/lib/active_record/collection_cache_key.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +110 -35
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +157 -29
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +7 -2
  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 +149 -78
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +81 -96
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  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 +2 -0
  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 +6 -0
  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 +3 -1
  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 +14 -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 +248 -112
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
  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 +20 -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 +79 -92
  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 +39 -60
  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 +17 -13
  133. data/lib/active_record/errors.rb +42 -3
  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 +4 -2
  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 +40 -2
  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 +196 -48
  156. data/lib/active_record/query_cache.rb +12 -14
  157. data/lib/active_record/querying.rb +3 -1
  158. data/lib/active_record/railtie.rb +61 -3
  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 +110 -192
  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 +31 -9
  167. data/lib/active_record/relation/delegation.rb +15 -27
  168. data/lib/active_record/relation/finder_methods.rb +71 -76
  169. data/lib/active_record/relation/from_clause.rb +2 -8
  170. data/lib/active_record/relation/merger.rb +47 -20
  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 +55 -79
  179. data/lib/active_record/relation/query_attribute.rb +26 -2
  180. data/lib/active_record/relation/query_methods.rb +95 -91
  181. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  182. data/lib/active_record/relation/spawn_methods.rb +3 -1
  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 +106 -219
  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 +6 -7
  193. data/lib/active_record/scoping/named.rb +21 -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 +22 -12
  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 +25 -14
  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 +32 -27
  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 +23 -36
  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,4 +1,6 @@
1
- require "active_record/attribute/user_provided_default"
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/attribute/user_provided_default"
2
4
 
3
5
  module ActiveRecord
4
6
  # See ActiveRecord::Attributes::ClassMethods for documentation
@@ -6,8 +8,7 @@ module ActiveRecord
6
8
  extend ActiveSupport::Concern
7
9
 
8
10
  included do
9
- class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false # :internal:
10
- self.attributes_to_define_after_schema_loads = {}
11
+ class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
11
12
  end
12
13
 
13
14
  module ClassMethods
@@ -56,7 +57,7 @@ module ActiveRecord
56
57
  # store_listing = StoreListing.new(price_in_cents: '10.1')
57
58
  #
58
59
  # # before
59
- # store_listing.price_in_cents # => BigDecimal.new(10.1)
60
+ # store_listing.price_in_cents # => BigDecimal(10.1)
60
61
  #
61
62
  # class StoreListing < ActiveRecord::Base
62
63
  # attribute :price_in_cents, :integer
@@ -249,14 +250,14 @@ module ActiveRecord
249
250
  if value == NO_DEFAULT_PROVIDED
250
251
  default_attribute = _default_attributes[name].with_type(type)
251
252
  elsif from_user
252
- default_attribute = Attribute::UserProvidedDefault.new(
253
+ default_attribute = ActiveModel::Attribute::UserProvidedDefault.new(
253
254
  name,
254
255
  value,
255
256
  type,
256
257
  _default_attributes.fetch(name.to_s) { nil },
257
258
  )
258
259
  else
259
- default_attribute = Attribute.from_database(name, value, type)
260
+ default_attribute = ActiveModel::Attribute.from_database(name, value, type)
260
261
  end
261
262
  _default_attributes[name] = default_attribute
262
263
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record Autosave Association
3
5
  #
@@ -140,8 +142,7 @@ module ActiveRecord
140
142
 
141
143
  included do
142
144
  Associations::Builder::Association.extensions << AssociationBuilderExtension
143
- mattr_accessor :index_nested_attribute_errors, instance_writer: false
144
- self.index_nested_attribute_errors = false
145
+ mattr_accessor :index_nested_attribute_errors, instance_writer: false, default: false
145
146
  end
146
147
 
147
148
  module ClassMethods # :nodoc:
@@ -216,13 +217,7 @@ module ActiveRecord
216
217
  method = :validate_single_association
217
218
  end
218
219
 
219
- define_non_cyclic_method(validation_method) do
220
- send(method, reflection)
221
- # TODO: remove the following line as soon as the return value of
222
- # callbacks is ignored, that is, returning `false` does not
223
- # display a deprecation warning or halts the callback chain.
224
- true
225
- end
220
+ define_non_cyclic_method(validation_method) { send(method, reflection) }
226
221
  validate validation_method
227
222
  after_validation :_ensure_no_duplicate_errors
228
223
  end
@@ -369,7 +364,6 @@ module ActiveRecord
369
364
  # association whether or not the parent was a new record before saving.
370
365
  def before_save_collection_association
371
366
  @new_record_before_save = new_record?
372
- true
373
367
  end
374
368
 
375
369
  def after_save_collection_association
@@ -389,7 +383,7 @@ module ActiveRecord
389
383
  autosave = reflection.options[:autosave]
390
384
 
391
385
  # reconstruct the scope now that we know the owner's id
392
- association.reset_scope if association.respond_to?(:reset_scope)
386
+ association.reset_scope
393
387
 
394
388
  if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
395
389
  if autosave
@@ -398,7 +392,7 @@ module ActiveRecord
398
392
  records -= records_to_destroy
399
393
  end
400
394
 
401
- records.each do |record|
395
+ records.each_with_index do |record, index|
402
396
  next if record.destroyed?
403
397
 
404
398
  saved = true
@@ -406,8 +400,13 @@ module ActiveRecord
406
400
  if autosave != false && (@new_record_before_save || record.new_record?)
407
401
  if autosave
408
402
  saved = association.insert_record(record, false)
409
- else
410
- association.insert_record(record) unless reflection.nested?
403
+ elsif !reflection.nested?
404
+ if reflection.validate?
405
+ valid = association_valid?(reflection, record, index)
406
+ saved = valid ? association.insert_record(record, false) : false
407
+ else
408
+ association.insert_record(record)
409
+ end
411
410
  end
412
411
  elsif autosave
413
412
  saved = record.save(validate: false)
@@ -442,6 +441,9 @@ module ActiveRecord
442
441
  if (autosave && record.changed_for_autosave?) || new_record? || record_changed?(reflection, record, key)
443
442
  unless reflection.through_reflection
444
443
  record[reflection.foreign_key] = key
444
+ if inverse_reflection = reflection.inverse_of
445
+ record.association(inverse_reflection.name).loaded!
446
+ end
445
447
  end
446
448
 
447
449
  saved = record.save(validate: !autosave)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
2
4
  require "active_support/benchmarkable"
3
5
  require "active_support/dependencies"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # = Active Record \Callbacks
3
5
  #
@@ -96,9 +98,9 @@ module ActiveRecord
96
98
  # == Types of callbacks
97
99
  #
98
100
  # There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
99
- # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects
101
+ # inline methods (using a proc). Method references and callback objects
100
102
  # are the recommended approaches, inline methods using a proc are sometimes appropriate (such as for
101
- # creating mix-ins), and inline eval methods are deprecated.
103
+ # creating mix-ins).
102
104
  #
103
105
  # The method reference callbacks work by specifying a protected or private method available in the object, like this:
104
106
  #
@@ -230,7 +232,7 @@ module ActiveRecord
230
232
  #
231
233
  # For example:
232
234
  #
233
- # class Topic
235
+ # class Topic < ActiveRecord::Base
234
236
  # has_many :children
235
237
  #
236
238
  # after_save :log_children
@@ -238,7 +240,7 @@ module ActiveRecord
238
240
  #
239
241
  # private
240
242
  #
241
- # def log_chidren
243
+ # def log_children
242
244
  # # Child processing
243
245
  # end
244
246
  #
@@ -255,7 +257,7 @@ module ActiveRecord
255
257
  #
256
258
  # For example:
257
259
  #
258
- # class Topic
260
+ # class Topic < ActiveRecord::Base
259
261
  # has_many :children
260
262
  #
261
263
  # after_commit :log_children
@@ -263,7 +265,7 @@ module ActiveRecord
263
265
  #
264
266
  # private
265
267
  #
266
- # def log_chidren
268
+ # def log_children
267
269
  # # Child processing
268
270
  # end
269
271
  #
@@ -330,6 +332,10 @@ module ActiveRecord
330
332
  _run_touch_callbacks { super }
331
333
  end
332
334
 
335
+ def increment!(*, touch: nil) # :nodoc:
336
+ touch ? _run_touch_callbacks { super } : super
337
+ end
338
+
333
339
  private
334
340
 
335
341
  def create_or_update(*)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Coders # :nodoc:
3
5
  class JSON # :nodoc:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
2
4
 
3
5
  module ActiveRecord
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module CollectionCacheKey
3
5
  def collection_cache_key(collection = all, timestamp_column = :updated_at) # :nodoc:
4
- query_signature = Digest::MD5.hexdigest(collection.to_sql)
6
+ query_signature = ActiveSupport::Digest.hexdigest(collection.to_sql)
5
7
  key = "#{collection.model_name.cache_key}/query-#{query_signature}"
6
8
 
7
9
  if collection.loaded? || collection.distinct_value
@@ -10,24 +12,26 @@ module ActiveRecord
10
12
  timestamp = collection.max_by(&timestamp_column)._read_attribute(timestamp_column)
11
13
  end
12
14
  else
13
- column_type = type_for_attribute(timestamp_column.to_s)
14
- column = "#{connection.quote_table_name(collection.table_name)}.#{connection.quote_column_name(timestamp_column)}"
15
+ if collection.eager_loading?
16
+ collection = collection.send(:apply_join_dependency)
17
+ end
18
+ column_type = type_for_attribute(timestamp_column)
19
+ column = connection.column_name_from_arel_node(collection.arel_attribute(timestamp_column))
15
20
  select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
16
21
 
17
22
  if collection.has_limit_or_offset?
18
- query = collection.spawn
19
- query.select_values = [column]
23
+ query = collection.select(column)
20
24
  subquery_alias = "subquery_for_cache_key"
21
25
  subquery_column = "#{subquery_alias}.#{timestamp_column}"
22
26
  subquery = query.arel.as(subquery_alias)
23
- arel = Arel::SelectManager.new(query.engine).project(select_values % subquery_column).from(subquery)
27
+ arel = Arel::SelectManager.new(subquery).project(select_values % subquery_column)
24
28
  else
25
29
  query = collection.unscope(:order)
26
30
  query.select_values = [select_values % column]
27
31
  arel = query.arel
28
32
  end
29
33
 
30
- result = connection.select_one(arel, nil, query.bound_attributes)
34
+ result = connection.select_one(arel, nil)
31
35
 
32
36
  if result.blank?
33
37
  size = 0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
  require "concurrent/map"
3
5
  require "monitor"
@@ -61,15 +63,13 @@ module ActiveRecord
61
63
  # There are several connection-pooling-related options that you can add to
62
64
  # your database connection configuration:
63
65
  #
64
- # * +pool+: number indicating size of connection pool (default 5)
65
- # * +checkout_timeout+: number of seconds to block and wait for a connection
66
- # before giving up and raising a timeout error (default 5 seconds).
67
- # * +reaping_frequency+: frequency in seconds to periodically run the
68
- # Reaper, which attempts to find and recover connections from dead
69
- # threads, which can occur if a programmer forgets to close a
70
- # connection at the end of a thread or a thread dies unexpectedly.
71
- # Regardless of this setting, the Reaper will be invoked before every
72
- # blocking wait. (Default +nil+, which means don't schedule the Reaper).
66
+ # * +pool+: maximum number of connections the pool may manage (default 5).
67
+ # * +idle_timeout+: number of seconds that a connection will be kept
68
+ # unused in the pool before it is automatically disconnected (default
69
+ # 300 seconds). Set this to zero to keep connections forever.
70
+ # * +checkout_timeout+: number of seconds to wait for a connection to
71
+ # become available before giving up and raising a timeout error (default
72
+ # 5 seconds).
73
73
  #
74
74
  #--
75
75
  # Synchronization policy:
@@ -80,11 +80,8 @@ module ActiveRecord
80
80
  # * private methods that require being called in a +synchronize+ blocks
81
81
  # are now explicitly documented
82
82
  class ConnectionPool
83
- # Threadsafe, fair, FIFO queue. Meant to be used by ConnectionPool
84
- # with which it shares a Monitor. But could be a generic Queue.
85
- #
86
- # The Queue in stdlib's 'thread' could replace this class except
87
- # stdlib's doesn't support waiting with a timeout.
83
+ # Threadsafe, fair, LIFO queue. Meant to be used by ConnectionPool
84
+ # with which it shares a Monitor.
88
85
  class Queue
89
86
  def initialize(lock = Monitor.new)
90
87
  @lock = lock
@@ -173,7 +170,7 @@ module ActiveRecord
173
170
 
174
171
  # Removes and returns the head of the queue if possible, or +nil+.
175
172
  def remove
176
- @queue.shift
173
+ @queue.pop
177
174
  end
178
175
 
179
176
  # Remove and return the head the queue if the number of
@@ -268,7 +265,7 @@ module ActiveRecord
268
265
  # Connections must be leased while holding the main pool mutex. This is
269
266
  # an internal subclass that also +.leases+ returned connections while
270
267
  # still in queue's critical section (queue synchronizes with the same
271
- # +@lock+ as the main pool) so that a returned connection is already
268
+ # <tt>@lock</tt> as the main pool) so that a returned connection is already
272
269
  # leased and there is no need to re-enter synchronized block.
273
270
  class ConnectionLeasingQueue < Queue # :nodoc:
274
271
  include BiasableQueue
@@ -281,12 +278,12 @@ module ActiveRecord
281
278
  end
282
279
  end
283
280
 
284
- # Every +frequency+ seconds, the reaper will call +reap+ on +pool+.
285
- # A reaper instantiated with a +nil+ frequency will never reap the
286
- # connection pool.
281
+ # Every +frequency+ seconds, the reaper will call +reap+ and +flush+ on
282
+ # +pool+. A reaper instantiated with a zero frequency will never reap
283
+ # the connection pool.
287
284
  #
288
- # Configure the frequency by setting "reaping_frequency" in your
289
- # database yaml file.
285
+ # Configure the frequency by setting +reaping_frequency+ in your database
286
+ # yaml file (default 60 seconds).
290
287
  class Reaper
291
288
  attr_reader :pool, :frequency
292
289
 
@@ -296,11 +293,12 @@ module ActiveRecord
296
293
  end
297
294
 
298
295
  def run
299
- return unless frequency
296
+ return unless frequency && frequency > 0
300
297
  Thread.new(frequency, pool) { |t, p|
301
298
  loop do
302
299
  sleep t
303
300
  p.reap
301
+ p.flush
304
302
  end
305
303
  }
306
304
  end
@@ -324,8 +322,10 @@ module ActiveRecord
324
322
  @spec = spec
325
323
 
326
324
  @checkout_timeout = (spec.config[:checkout_timeout] && spec.config[:checkout_timeout].to_f) || 5
327
- @reaper = Reaper.new(self, (spec.config[:reaping_frequency] && spec.config[:reaping_frequency].to_f))
328
- @reaper.run
325
+ if @idle_timeout = spec.config.fetch(:idle_timeout, 300)
326
+ @idle_timeout = @idle_timeout.to_f
327
+ @idle_timeout = nil if @idle_timeout <= 0
328
+ end
329
329
 
330
330
  # default max pool size to 5
331
331
  @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
@@ -338,7 +338,7 @@ module ActiveRecord
338
338
  # then that +thread+ does indeed own that +conn+. However, an absence of a such
339
339
  # mapping does not mean that the +thread+ doesn't own the said connection. In
340
340
  # that case +conn.owner+ attr should be consulted.
341
- # Access and modification of +@thread_cached_conns+ does not require
341
+ # Access and modification of <tt>@thread_cached_conns</tt> does not require
342
342
  # synchronization.
343
343
  @thread_cached_conns = Concurrent::Map.new(initial_capacity: @size)
344
344
 
@@ -355,6 +355,12 @@ module ActiveRecord
355
355
  @available = ConnectionLeasingQueue.new self
356
356
 
357
357
  @lock_thread = false
358
+
359
+ # +reaping_frequency+ is configurable mostly for historical reasons, but it could
360
+ # also be useful if someone wants a very low +idle_timeout+.
361
+ reaping_frequency = spec.config.fetch(:reaping_frequency, 60)
362
+ @reaper = Reaper.new(self, reaping_frequency && reaping_frequency.to_f)
363
+ @reaper.run
358
364
  end
359
365
 
360
366
  def lock_thread=(lock_thread)
@@ -447,6 +453,21 @@ module ActiveRecord
447
453
  disconnect(false)
448
454
  end
449
455
 
456
+ # Discards all connections in the pool (even if they're currently
457
+ # leased!), along with the pool itself. Any further interaction with the
458
+ # pool (except #spec and #schema_cache) is undefined.
459
+ #
460
+ # See AbstractAdapter#discard!
461
+ def discard! # :nodoc:
462
+ synchronize do
463
+ return if @connections.nil? # already discarded
464
+ @connections.each do |conn|
465
+ conn.discard!
466
+ end
467
+ @connections = @available = @thread_cached_conns = nil
468
+ end
469
+ end
470
+
450
471
  # Clears the cache which maps classes and re-connects connections that
451
472
  # require reloading.
452
473
  #
@@ -572,6 +593,35 @@ module ActiveRecord
572
593
  end
573
594
  end
574
595
 
596
+ # Disconnect all connections that have been idle for at least
597
+ # +minimum_idle+ seconds. Connections currently checked out, or that were
598
+ # checked in less than +minimum_idle+ seconds ago, are unaffected.
599
+ def flush(minimum_idle = @idle_timeout)
600
+ return if minimum_idle.nil?
601
+
602
+ idle_connections = synchronize do
603
+ @connections.select do |conn|
604
+ !conn.in_use? && conn.seconds_idle >= minimum_idle
605
+ end.each do |conn|
606
+ conn.lease
607
+
608
+ @available.delete conn
609
+ @connections.delete conn
610
+ end
611
+ end
612
+
613
+ idle_connections.each do |conn|
614
+ conn.disconnect!
615
+ end
616
+ end
617
+
618
+ # Disconnect all currently idle connections. Connections currently checked
619
+ # out are unaffected.
620
+ def flush!
621
+ reap
622
+ flush(-1)
623
+ end
624
+
575
625
  def num_waiting_in_queue # :nodoc:
576
626
  @available.num_waiting
577
627
  end
@@ -679,7 +729,7 @@ module ActiveRecord
679
729
  # this block can't be easily moved into attempt_to_checkout_all_existing_connections's
680
730
  # rescue block, because doing so would put it outside of synchronize section, without
681
731
  # being in a critical section thread_report might become inaccurate
682
- msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds"
732
+ msg = "could not obtain ownership of all database connections in #{checkout_timeout} seconds".dup
683
733
 
684
734
  thread_report = []
685
735
  @connections.each do |conn|
@@ -734,10 +784,10 @@ module ActiveRecord
734
784
  # Implementation detail: the connection returned by +acquire_connection+
735
785
  # will already be "+connection.lease+ -ed" to the current thread.
736
786
  def acquire_connection(checkout_timeout)
737
- # NOTE: we rely on +@available.poll+ and +try_to_checkout_new_connection+ to
787
+ # NOTE: we rely on <tt>@available.poll</tt> and +try_to_checkout_new_connection+ to
738
788
  # +conn.lease+ the returned connection (and to do this in a +synchronized+
739
789
  # section). This is not the cleanest implementation, as ideally we would
740
- # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to +@available.poll+
790
+ # <tt>synchronize { conn.lease }</tt> in this method, but by leaving it to <tt>@available.poll</tt>
741
791
  # and +try_to_checkout_new_connection+ we can piggyback on +synchronize+ sections
742
792
  # of the said methods and avoid an additional +synchronize+ overhead.
743
793
  if conn = @available.poll || try_to_checkout_new_connection
@@ -761,7 +811,7 @@ module ActiveRecord
761
811
  end
762
812
  end
763
813
 
764
- # If the pool is not at a +@size+ limit, establish new connection. Connecting
814
+ # If the pool is not at a <tt>@size</tt> limit, establish new connection. Connecting
765
815
  # to the DB is done outside main synchronized section.
766
816
  #--
767
817
  # Implementation constraint: a newly established connection returned by this
@@ -827,7 +877,7 @@ module ActiveRecord
827
877
  # end
828
878
  #
829
879
  # class Book < ActiveRecord::Base
830
- # establish_connection "library_db"
880
+ # establish_connection :library_db
831
881
  # end
832
882
  #
833
883
  # class ScaryBook < Book
@@ -859,15 +909,35 @@ module ActiveRecord
859
909
  # All Active Record models use this handler to determine the connection pool that they
860
910
  # should use.
861
911
  #
862
- # The ConnectionHandler class is not coupled with the Active models, as it has no knowlodge
912
+ # The ConnectionHandler class is not coupled with the Active models, as it has no knowledge
863
913
  # about the model. The model needs to pass a specification name to the handler,
864
- # in order to lookup the correct connection pool.
914
+ # in order to look up the correct connection pool.
865
915
  class ConnectionHandler
916
+ def self.unowned_pool_finalizer(pid_map) # :nodoc:
917
+ lambda do |_|
918
+ discard_unowned_pools(pid_map)
919
+ end
920
+ end
921
+
922
+ def self.discard_unowned_pools(pid_map) # :nodoc:
923
+ pid_map.each do |pid, pools|
924
+ pools.values.compact.each(&:discard!) unless pid == Process.pid
925
+ end
926
+ end
927
+
866
928
  def initialize
867
929
  # These caches are keyed by spec.name (ConnectionSpecification#name).
868
930
  @owner_to_pool = Concurrent::Map.new(initial_capacity: 2) do |h, k|
931
+ # Discard the parent's connection pools immediately; we have no need
932
+ # of them
933
+ ConnectionHandler.discard_unowned_pools(h)
934
+
869
935
  h[k] = Concurrent::Map.new(initial_capacity: 2)
870
936
  end
937
+
938
+ # Backup finalizer: if the forked child never needed a pool, the above
939
+ # early discard has not occurred
940
+ ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
871
941
  end
872
942
 
873
943
  def connection_pool_list
@@ -921,6 +991,13 @@ module ActiveRecord
921
991
  connection_pool_list.each(&:disconnect!)
922
992
  end
923
993
 
994
+ # Disconnects all currently idle connections.
995
+ #
996
+ # See ConnectionPool#flush! for details.
997
+ def flush_idle_connections!
998
+ connection_pool_list.each(&:flush!)
999
+ end
1000
+
924
1001
  # Locate the connection of the nearest super class. This can be an
925
1002
  # active or defined connection: if it is the latter, it will be
926
1003
  # opened and set as the active connection for the class it was defined
@@ -928,9 +1005,7 @@ module ActiveRecord
928
1005
  def retrieve_connection(spec_name) #:nodoc:
929
1006
  pool = retrieve_connection_pool(spec_name)
930
1007
  raise ConnectionNotEstablished, "No connection pool with '#{spec_name}' found." unless pool
931
- conn = pool.connection
932
- raise ConnectionNotEstablished, "No connection for '#{spec_name}' in connection pool" unless conn
933
- conn
1008
+ pool.connection
934
1009
  end
935
1010
 
936
1011
  # Returns true if a connection that's accessible to this class has
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters # :nodoc:
3
5
  module DatabaseLimits