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
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2004-2019 David Heinemeier Hansson
1
+ Copyright (c) 2004-2020 David Heinemeier Hansson
2
2
 
3
3
  Arel originally copyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson
4
4
 
data/README.rdoc CHANGED
@@ -132,7 +132,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
132
132
  SQLite3[link:classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
133
133
 
134
134
 
135
- * Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc].
135
+ * Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[https://ruby-doc.org/stdlib/libdoc/logger/rdoc/].
136
136
 
137
137
  ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
138
138
  ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
@@ -140,7 +140,7 @@ This would also define the following accessors: <tt>Product#name</tt> and
140
140
 
141
141
  * Database agnostic schema management with Migrations.
142
142
 
143
- class AddSystemSettings < ActiveRecord::Migration[5.0]
143
+ class AddSystemSettings < ActiveRecord::Migration[6.0]
144
144
  def up
145
145
  create_table :system_settings do |t|
146
146
  t.string :name
@@ -194,7 +194,7 @@ The latest version of Active Record can be installed with RubyGems:
194
194
 
195
195
  Source code can be downloaded as part of the Rails project on GitHub:
196
196
 
197
- * https://github.com/rails/rails/tree/master/activerecord
197
+ * https://github.com/rails/rails/tree/main/activerecord
198
198
 
199
199
 
200
200
  == License
data/lib/active_record.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2019 David Heinemeier Hansson
4
+ # Copyright (c) 2004-2020 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -31,17 +31,18 @@ require "yaml"
31
31
 
32
32
  require "active_record/version"
33
33
  require "active_model/attribute_set"
34
+ require "active_record/errors"
34
35
 
35
36
  module ActiveRecord
36
37
  extend ActiveSupport::Autoload
37
38
 
38
- autoload :AdvisoryLockBase
39
39
  autoload :Base
40
40
  autoload :Callbacks
41
41
  autoload :Core
42
42
  autoload :ConnectionHandling
43
43
  autoload :CounterCache
44
44
  autoload :DynamicMatchers
45
+ autoload :DelegatedType
45
46
  autoload :Enum
46
47
  autoload :InternalMetadata
47
48
  autoload :Explain
@@ -68,18 +69,17 @@ module ActiveRecord
68
69
  autoload :Serialization
69
70
  autoload :StatementCache
70
71
  autoload :Store
72
+ autoload :SignedId
71
73
  autoload :Suppressor
72
74
  autoload :Timestamp
73
75
  autoload :Transactions
74
76
  autoload :Translation
75
77
  autoload :Validations
76
78
  autoload :SecureToken
77
- autoload :DatabaseSelector, "active_record/middleware/database_selector"
79
+ autoload :DestroyAssociationAsyncJob
78
80
 
79
81
  eager_autoload do
80
- autoload :ActiveRecordError, "active_record/errors"
81
- autoload :ConnectionNotEstablished, "active_record/errors"
82
- autoload :ConnectionAdapters, "active_record/connection_adapters/abstract_adapter"
82
+ autoload :ConnectionAdapters
83
83
 
84
84
  autoload :Aggregations
85
85
  autoload :Associations
@@ -137,14 +137,6 @@ module ActiveRecord
137
137
  end
138
138
  end
139
139
 
140
- module ConnectionAdapters
141
- extend ActiveSupport::Autoload
142
-
143
- eager_autoload do
144
- autoload :AbstractAdapter
145
- end
146
- end
147
-
148
140
  module Scoping
149
141
  extend ActiveSupport::Autoload
150
142
 
@@ -194,3 +186,4 @@ end
194
186
  YAML.load_tags["!ruby/object:ActiveRecord::AttributeSet"] = "ActiveModel::AttributeSet"
195
187
  YAML.load_tags["!ruby/object:ActiveRecord::Attribute::FromDatabase"] = "ActiveModel::Attribute::FromDatabase"
196
188
  YAML.load_tags["!ruby/object:ActiveRecord::LazyAttributeHash"] = "ActiveModel::LazyAttributeHash"
189
+ YAML.load_tags["!ruby/object:ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString"] = "ActiveRecord::Type::String"
@@ -141,7 +141,7 @@ module ActiveRecord
141
141
  # converted to an instance of value class if necessary.
142
142
  #
143
143
  # For example, the +NetworkResource+ model has +network_address+ and +cidr_range+ attributes that should be
144
- # aggregated using the +NetAddr::CIDR+ value class (http://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR).
144
+ # aggregated using the +NetAddr::CIDR+ value class (https://www.rubydoc.info/gems/netaddr/1.5.0/NetAddr/CIDR).
145
145
  # The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter.
146
146
  # New values can be assigned to the value object using either another +NetAddr::CIDR+ object, a string
147
147
  # or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
@@ -244,8 +244,8 @@ module ActiveRecord
244
244
  private
245
245
  def reader_method(name, class_name, mapping, allow_nil, constructor)
246
246
  define_method(name) do
247
- if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? { |key, _| !_read_attribute(key).nil? })
248
- attrs = mapping.collect { |key, _| _read_attribute(key) }
247
+ if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? { |key, _| !read_attribute(key).nil? })
248
+ attrs = mapping.collect { |key, _| read_attribute(key) }
249
249
  object = constructor.respond_to?(:call) ?
250
250
  constructor.call(*attrs) :
251
251
  class_name.constantize.send(constructor, *attrs)
@@ -271,10 +271,10 @@ module ActiveRecord
271
271
  end
272
272
 
273
273
  if part.nil? && allow_nil
274
- mapping.each { |key, _| self[key] = nil }
274
+ mapping.each { |key, _| write_attribute(key, nil) }
275
275
  @aggregation_cache[name] = nil
276
276
  else
277
- mapping.each { |key, value| self[key] = part.send(value) }
277
+ mapping.each { |key, value| write_attribute(key, part.send(value)) }
278
278
  @aggregation_cache[name] = part.freeze
279
279
  end
280
280
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- class AssociationRelation < Relation
4
+ class AssociationRelation < Relation # :nodoc:
5
5
  def initialize(klass, association, **)
6
6
  super(klass)
7
7
  @association = association
@@ -15,23 +15,41 @@ module ActiveRecord
15
15
  other == records
16
16
  end
17
17
 
18
- def build(attributes = nil, &block)
19
- block = _deprecated_scope_block("new", &block)
20
- scoping { @association.build(attributes, &block) }
21
- end
22
- alias new build
18
+ %w(insert insert_all insert! insert_all! upsert upsert_all).each do |method|
19
+ class_eval <<~RUBY
20
+ def #{method}(attributes, **kwargs)
21
+ if @association.reflection.through_reflection?
22
+ raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
23
+ end
23
24
 
24
- def create(attributes = nil, &block)
25
- block = _deprecated_scope_block("create", &block)
26
- scoping { @association.create(attributes, &block) }
25
+ scoping { klass.#{method}(attributes, **kwargs) }
26
+ end
27
+ RUBY
27
28
  end
28
29
 
29
- def create!(attributes = nil, &block)
30
- block = _deprecated_scope_block("create!", &block)
31
- scoping { @association.create!(attributes, &block) }
30
+ def build(attributes = nil, &block)
31
+ if attributes.is_a?(Array)
32
+ attributes.collect { |attr| build(attr, &block) }
33
+ else
34
+ block = current_scope_restoring_block(&block)
35
+ scoping { _new(attributes, &block) }
36
+ end
32
37
  end
38
+ alias new build
33
39
 
34
40
  private
41
+ def _new(attributes, &block)
42
+ @association.build(attributes, &block)
43
+ end
44
+
45
+ def _create(attributes, &block)
46
+ @association.create(attributes, &block)
47
+ end
48
+
49
+ def _create!(attributes, &block)
50
+ @association.create!(attributes, &block)
51
+ end
52
+
35
53
  def exec_queries
36
54
  super do |record|
37
55
  @association.set_inverse_instance_from_queries(record)
@@ -2,38 +2,116 @@
2
2
 
3
3
  require "active_support/core_ext/enumerable"
4
4
  require "active_support/core_ext/string/conversions"
5
- require "active_support/core_ext/module/remove_method"
6
- require "active_record/errors"
7
5
 
8
6
  module ActiveRecord
9
7
  class AssociationNotFoundError < ConfigurationError #:nodoc:
8
+ attr_reader :record, :association_name
10
9
  def initialize(record = nil, association_name = nil)
10
+ @record = record
11
+ @association_name = association_name
11
12
  if record && association_name
12
13
  super("Association named '#{association_name}' was not found on #{record.class.name}; perhaps you misspelled it?")
13
14
  else
14
15
  super("Association was not found.")
15
16
  end
16
17
  end
18
+
19
+ class Correction
20
+ def initialize(error)
21
+ @error = error
22
+ end
23
+
24
+ def corrections
25
+ if @error.association_name
26
+ maybe_these = @error.record.class.reflections.keys
27
+
28
+ maybe_these.sort_by { |n|
29
+ DidYouMean::Jaro.distance(@error.association_name.to_s, n)
30
+ }.reverse.first(4)
31
+ else
32
+ []
33
+ end
34
+ end
35
+ end
36
+
37
+ # We may not have DYM, and DYM might not let us register error handlers
38
+ if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
39
+ DidYouMean.correct_error(self, Correction)
40
+ end
17
41
  end
18
42
 
19
43
  class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
44
+ attr_reader :reflection, :associated_class
20
45
  def initialize(reflection = nil, associated_class = nil)
21
46
  if reflection
47
+ @reflection = reflection
48
+ @associated_class = associated_class.nil? ? reflection.klass : associated_class
22
49
  super("Could not find the inverse association for #{reflection.name} (#{reflection.options[:inverse_of].inspect} in #{associated_class.nil? ? reflection.class_name : associated_class.name})")
23
50
  else
24
51
  super("Could not find the inverse association.")
25
52
  end
26
53
  end
54
+
55
+ class Correction
56
+ def initialize(error)
57
+ @error = error
58
+ end
59
+
60
+ def corrections
61
+ if @error.reflection && @error.associated_class
62
+ maybe_these = @error.associated_class.reflections.keys
63
+
64
+ maybe_these.sort_by { |n|
65
+ DidYouMean::Jaro.distance(@error.reflection.options[:inverse_of].to_s, n)
66
+ }.reverse.first(4)
67
+ else
68
+ []
69
+ end
70
+ end
71
+ end
72
+
73
+ # We may not have DYM, and DYM might not let us register error handlers
74
+ if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
75
+ DidYouMean.correct_error(self, Correction)
76
+ end
27
77
  end
28
78
 
29
79
  class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
30
- def initialize(owner_class_name = nil, reflection = nil)
31
- if owner_class_name && reflection
32
- super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class_name}")
80
+ attr_reader :owner_class, :reflection
81
+
82
+ def initialize(owner_class = nil, reflection = nil)
83
+ if owner_class && reflection
84
+ @owner_class = owner_class
85
+ @reflection = reflection
86
+ super("Could not find the association #{reflection.options[:through].inspect} in model #{owner_class.name}")
33
87
  else
34
88
  super("Could not find the association.")
35
89
  end
36
90
  end
91
+
92
+ class Correction
93
+ def initialize(error)
94
+ @error = error
95
+ end
96
+
97
+ def corrections
98
+ if @error.reflection && @error.owner_class
99
+ maybe_these = @error.owner_class.reflections.keys
100
+ maybe_these -= [@error.reflection.name.to_s] # remove failing reflection
101
+
102
+ maybe_these.sort_by { |n|
103
+ DidYouMean::Jaro.distance(@error.reflection.options[:through].to_s, n)
104
+ }.reverse.first(4)
105
+ else
106
+ []
107
+ end
108
+ end
109
+ end
110
+
111
+ # We may not have DYM, and DYM might not let us register error handlers
112
+ if defined?(DidYouMean) && DidYouMean.respond_to?(:correct_error)
113
+ DidYouMean.correct_error(self, Correction)
114
+ end
37
115
  end
38
116
 
39
117
  class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
@@ -702,9 +780,8 @@ module ActiveRecord
702
780
  # inverse detection only works on #has_many, #has_one, and
703
781
  # #belongs_to associations.
704
782
  #
705
- # Extra options on the associations, as defined in the
706
- # <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt>
707
- # constant, or a custom scope, will also prevent the association's inverse
783
+ # <tt>:foreign_key</tt> and <tt>:through</tt> options on the associations,
784
+ # or a custom scope, will also prevent the association's inverse
708
785
  # from being found automatically.
709
786
  #
710
787
  # The automatic guessing of the inverse association uses a heuristic based
@@ -1292,7 +1369,11 @@ module ActiveRecord
1292
1369
  # similar callbacks may affect the <tt>:dependent</tt> behavior, and the
1293
1370
  # <tt>:dependent</tt> behavior may affect other callbacks.
1294
1371
  #
1372
+ # * <tt>nil</tt> do nothing (default).
1295
1373
  # * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
1374
+ # * <tt>:destroy_async</tt> destroys all the associated objects in a background job. <b>WARNING:</b> Do not use
1375
+ # this option if the association is backed by foreign key constraints in your database. The foreign key
1376
+ # constraint actions will occur inside the same transaction that deletes its owner.
1296
1377
  # * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
1297
1378
  # * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Polymorphic type will also be nullified
1298
1379
  # on polymorphic associations. Callbacks are not executed.
@@ -1357,6 +1438,11 @@ module ActiveRecord
1357
1438
  # Specifies a module or array of modules that will be extended into the association object returned.
1358
1439
  # Useful for defining methods on associations, especially when they should be shared between multiple
1359
1440
  # association objects.
1441
+ # [:strict_loading]
1442
+ # Enforces strict loading every time the associated record is loaded through this association.
1443
+ # [:ensuring_owner_was]
1444
+ # Specifies an instance method to be called on the owner. The method must return true in order for the
1445
+ # associated records to be deleted in a background job.
1360
1446
  #
1361
1447
  # Option examples:
1362
1448
  # has_many :comments, -> { order("posted_on") }
@@ -1367,6 +1453,7 @@ module ActiveRecord
1367
1453
  # has_many :tags, as: :taggable
1368
1454
  # has_many :reports, -> { readonly }
1369
1455
  # has_many :subscribers, through: :subscriptions, source: :user
1456
+ # has_many :comments, strict_loading: true
1370
1457
  def has_many(name, scope = nil, **options, &extension)
1371
1458
  reflection = Builder::HasMany.build(self, name, scope, options, &extension)
1372
1459
  Reflection.add_reflection self, name, reflection
@@ -1436,7 +1523,11 @@ module ActiveRecord
1436
1523
  # Controls what happens to the associated object when
1437
1524
  # its owner is destroyed:
1438
1525
  #
1526
+ # * <tt>nil</tt> do nothing (default).
1439
1527
  # * <tt>:destroy</tt> causes the associated object to also be destroyed
1528
+ # * <tt>:destroy_async</tt> causes the associated object to be destroyed in a background job. <b>WARNING:</b> Do not use
1529
+ # this option if the association is backed by foreign key constraints in your database. The foreign key
1530
+ # constraint actions will occur inside the same transaction that deletes its owner.
1440
1531
  # * <tt>:delete</tt> causes the associated object to be deleted directly from the database (so callbacks will not execute)
1441
1532
  # * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Polymorphic type column is also nullified
1442
1533
  # on polymorphic associations. Callbacks are not executed.
@@ -1495,6 +1586,11 @@ module ActiveRecord
1495
1586
  # When set to +true+, the association will also have its presence validated.
1496
1587
  # This will validate the association itself, not the id. You can use
1497
1588
  # +:inverse_of+ to avoid an extra query during validation.
1589
+ # [:strict_loading]
1590
+ # Enforces strict loading every time the associated record is loaded through this association.
1591
+ # [:ensuring_owner_was]
1592
+ # Specifies an instance method to be called on the owner. The method must return true in order for the
1593
+ # associated records to be deleted in a background job.
1498
1594
  #
1499
1595
  # Option examples:
1500
1596
  # has_one :credit_card, dependent: :destroy # destroys the associated credit card
@@ -1507,6 +1603,7 @@ module ActiveRecord
1507
1603
  # has_one :club, through: :membership
1508
1604
  # has_one :primary_address, -> { where(primary: true) }, through: :addressables, source: :addressable
1509
1605
  # has_one :credit_card, required: true
1606
+ # has_one :credit_card, strict_loading: true
1510
1607
  def has_one(name, scope = nil, **options)
1511
1608
  reflection = Builder::HasOne.build(self, name, scope, options)
1512
1609
  Reflection.add_reflection self, name, reflection
@@ -1588,7 +1685,8 @@ module ActiveRecord
1588
1685
  # By default this is +id+.
1589
1686
  # [:dependent]
1590
1687
  # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
1591
- # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method.
1688
+ # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. If set to
1689
+ # <tt>:destroy_async</tt>, the associated object is scheduled to be destroyed in a background job.
1592
1690
  # This option should not be specified when #belongs_to is used in conjunction with
1593
1691
  # a #has_many relationship on another class because of the potential to leave
1594
1692
  # orphaned records behind.
@@ -1640,6 +1738,11 @@ module ActiveRecord
1640
1738
  # [:default]
1641
1739
  # Provide a callable (i.e. proc or lambda) to specify that the association should
1642
1740
  # be initialized with a particular record before validation.
1741
+ # [:strict_loading]
1742
+ # Enforces strict loading every time the associated record is loaded through this association.
1743
+ # [:ensuring_owner_was]
1744
+ # Specifies an instance method to be called on the owner. The method must return true in order for the
1745
+ # associated records to be deleted in a background job.
1643
1746
  #
1644
1747
  # Option examples:
1645
1748
  # belongs_to :firm, foreign_key: "client_of"
@@ -1654,6 +1757,7 @@ module ActiveRecord
1654
1757
  # belongs_to :company, touch: :employees_last_updated_at
1655
1758
  # belongs_to :user, optional: true
1656
1759
  # belongs_to :account, default: -> { company.account }
1760
+ # belongs_to :account, strict_loading: true
1657
1761
  def belongs_to(name, scope = nil, **options)
1658
1762
  reflection = Builder::BelongsTo.build(self, name, scope, options)
1659
1763
  Reflection.add_reflection self, name, reflection
@@ -1676,7 +1780,7 @@ module ActiveRecord
1676
1780
  # The join table should not have a primary key or a model associated with it. You must manually generate the
1677
1781
  # join table with a migration such as this:
1678
1782
  #
1679
- # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[5.0]
1783
+ # class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration[6.0]
1680
1784
  # def change
1681
1785
  # create_join_table :developers, :projects
1682
1786
  # end
@@ -1816,6 +1920,8 @@ module ActiveRecord
1816
1920
  #
1817
1921
  # Note that NestedAttributes::ClassMethods#accepts_nested_attributes_for sets
1818
1922
  # <tt>:autosave</tt> to <tt>true</tt>.
1923
+ # [:strict_loading]
1924
+ # Enforces strict loading every time an associated record is loaded through this association.
1819
1925
  #
1820
1926
  # Option examples:
1821
1927
  # has_and_belongs_to_many :projects
@@ -1823,6 +1929,7 @@ module ActiveRecord
1823
1929
  # has_and_belongs_to_many :nations, class_name: "Country"
1824
1930
  # has_and_belongs_to_many :categories, join_table: "prods_cats"
1825
1931
  # has_and_belongs_to_many :categories, -> { readonly }
1932
+ # has_and_belongs_to_many :categories, strict_loading: true
1826
1933
  def has_and_belongs_to_many(name, scope = nil, **options, &extension)
1827
1934
  habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
1828
1935
 
@@ -1853,7 +1960,7 @@ module ActiveRecord
1853
1960
  hm_options[:through] = middle_reflection.name
1854
1961
  hm_options[:source] = join_model.right_reflection.name
1855
1962
 
1856
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend].each do |k|
1963
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name, :extend, :strict_loading].each do |k|
1857
1964
  hm_options[k] = options[k] if options.key? k
1858
1965
  end
1859
1966