activerecord 6.1.7.6 → 7.0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1575 -1016
  3. data/README.rdoc +3 -3
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/association_relation.rb +0 -10
  6. data/lib/active_record/associations/association.rb +33 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -3
  8. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  10. data/lib/active_record/associations/builder/association.rb +8 -2
  11. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  12. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  13. data/lib/active_record/associations/builder/has_many.rb +3 -2
  14. data/lib/active_record/associations/builder/has_one.rb +2 -1
  15. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  16. data/lib/active_record/associations/collection_association.rb +20 -22
  17. data/lib/active_record/associations/collection_proxy.rb +15 -5
  18. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  19. data/lib/active_record/associations/has_many_association.rb +8 -5
  20. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  21. data/lib/active_record/associations/has_one_association.rb +10 -7
  22. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency.rb +23 -15
  24. data/lib/active_record/associations/preloader/association.rb +186 -52
  25. data/lib/active_record/associations/preloader/batch.rb +48 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +138 -100
  32. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +8 -6
  39. data/lib/active_record/attribute_methods/serialization.rb +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +19 -22
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +8 -23
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +14 -16
  47. data/lib/active_record/coders/yaml_column.rb +4 -8
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +144 -82
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +115 -85
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -25
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -23
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  68. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  70. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  77. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  81. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  82. data/lib/active_record/connection_adapters/postgresql/quoting.rb +76 -73
  83. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  86. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
  88. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  89. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
  90. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +33 -18
  93. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
  94. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +19 -17
  95. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +98 -36
  96. data/lib/active_record/connection_adapters.rb +6 -5
  97. data/lib/active_record/connection_handling.rb +49 -55
  98. data/lib/active_record/core.rb +123 -148
  99. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  100. data/lib/active_record/database_configurations/database_config.rb +12 -9
  101. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  102. data/lib/active_record/database_configurations/url_config.rb +2 -2
  103. data/lib/active_record/database_configurations.rb +15 -32
  104. data/lib/active_record/delegated_type.rb +53 -12
  105. data/lib/active_record/destroy_association_async_job.rb +1 -1
  106. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  107. data/lib/active_record/dynamic_matchers.rb +1 -1
  108. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  109. data/lib/active_record/encryption/cipher.rb +53 -0
  110. data/lib/active_record/encryption/config.rb +44 -0
  111. data/lib/active_record/encryption/configurable.rb +67 -0
  112. data/lib/active_record/encryption/context.rb +35 -0
  113. data/lib/active_record/encryption/contexts.rb +72 -0
  114. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  115. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  116. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  117. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  118. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  119. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  120. data/lib/active_record/encryption/encryptor.rb +155 -0
  121. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  122. data/lib/active_record/encryption/errors.rb +15 -0
  123. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  124. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  125. data/lib/active_record/encryption/key.rb +28 -0
  126. data/lib/active_record/encryption/key_generator.rb +42 -0
  127. data/lib/active_record/encryption/key_provider.rb +46 -0
  128. data/lib/active_record/encryption/message.rb +33 -0
  129. data/lib/active_record/encryption/message_serializer.rb +90 -0
  130. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  131. data/lib/active_record/encryption/properties.rb +76 -0
  132. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  133. data/lib/active_record/encryption/scheme.rb +99 -0
  134. data/lib/active_record/encryption.rb +55 -0
  135. data/lib/active_record/enum.rb +50 -43
  136. data/lib/active_record/errors.rb +67 -4
  137. data/lib/active_record/explain_registry.rb +11 -6
  138. data/lib/active_record/explain_subscriber.rb +1 -1
  139. data/lib/active_record/fixture_set/file.rb +15 -1
  140. data/lib/active_record/fixture_set/table_row.rb +41 -6
  141. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  142. data/lib/active_record/fixtures.rb +20 -23
  143. data/lib/active_record/future_result.rb +139 -0
  144. data/lib/active_record/gem_version.rb +5 -5
  145. data/lib/active_record/inheritance.rb +55 -17
  146. data/lib/active_record/insert_all.rb +80 -14
  147. data/lib/active_record/integration.rb +4 -3
  148. data/lib/active_record/internal_metadata.rb +1 -5
  149. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  150. data/lib/active_record/locking/optimistic.rb +36 -21
  151. data/lib/active_record/locking/pessimistic.rb +10 -4
  152. data/lib/active_record/log_subscriber.rb +23 -7
  153. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  154. data/lib/active_record/middleware/database_selector.rb +18 -6
  155. data/lib/active_record/middleware/shard_selector.rb +60 -0
  156. data/lib/active_record/migration/command_recorder.rb +8 -9
  157. data/lib/active_record/migration/compatibility.rb +93 -46
  158. data/lib/active_record/migration/join_table.rb +1 -1
  159. data/lib/active_record/migration.rb +167 -87
  160. data/lib/active_record/model_schema.rb +58 -59
  161. data/lib/active_record/nested_attributes.rb +13 -12
  162. data/lib/active_record/no_touching.rb +3 -3
  163. data/lib/active_record/null_relation.rb +2 -6
  164. data/lib/active_record/persistence.rb +231 -61
  165. data/lib/active_record/query_cache.rb +2 -2
  166. data/lib/active_record/query_logs.rb +149 -0
  167. data/lib/active_record/querying.rb +16 -6
  168. data/lib/active_record/railtie.rb +136 -22
  169. data/lib/active_record/railties/controller_runtime.rb +4 -5
  170. data/lib/active_record/railties/databases.rake +78 -136
  171. data/lib/active_record/readonly_attributes.rb +11 -0
  172. data/lib/active_record/reflection.rb +80 -49
  173. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  174. data/lib/active_record/relation/batches.rb +6 -6
  175. data/lib/active_record/relation/calculations.rb +92 -60
  176. data/lib/active_record/relation/delegation.rb +7 -7
  177. data/lib/active_record/relation/finder_methods.rb +31 -35
  178. data/lib/active_record/relation/merger.rb +20 -13
  179. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
  180. data/lib/active_record/relation/predicate_builder.rb +1 -6
  181. data/lib/active_record/relation/query_attribute.rb +28 -11
  182. data/lib/active_record/relation/query_methods.rb +304 -68
  183. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  184. data/lib/active_record/relation/spawn_methods.rb +2 -2
  185. data/lib/active_record/relation/where_clause.rb +10 -19
  186. data/lib/active_record/relation.rb +189 -88
  187. data/lib/active_record/result.rb +23 -11
  188. data/lib/active_record/runtime_registry.rb +9 -13
  189. data/lib/active_record/sanitization.rb +17 -12
  190. data/lib/active_record/schema.rb +38 -23
  191. data/lib/active_record/schema_dumper.rb +29 -19
  192. data/lib/active_record/schema_migration.rb +4 -4
  193. data/lib/active_record/scoping/default.rb +60 -13
  194. data/lib/active_record/scoping/named.rb +3 -11
  195. data/lib/active_record/scoping.rb +64 -34
  196. data/lib/active_record/serialization.rb +6 -1
  197. data/lib/active_record/signed_id.rb +3 -3
  198. data/lib/active_record/store.rb +2 -2
  199. data/lib/active_record/suppressor.rb +11 -15
  200. data/lib/active_record/table_metadata.rb +6 -2
  201. data/lib/active_record/tasks/database_tasks.rb +127 -60
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  204. data/lib/active_record/test_databases.rb +1 -1
  205. data/lib/active_record/test_fixtures.rb +9 -6
  206. data/lib/active_record/timestamp.rb +3 -4
  207. data/lib/active_record/transactions.rb +12 -17
  208. data/lib/active_record/translation.rb +3 -3
  209. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  210. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  211. data/lib/active_record/type/internal/timezone.rb +2 -2
  212. data/lib/active_record/type/serialized.rb +9 -5
  213. data/lib/active_record/type/type_map.rb +17 -20
  214. data/lib/active_record/type.rb +1 -2
  215. data/lib/active_record/validations/associated.rb +4 -4
  216. data/lib/active_record/validations/presence.rb +2 -2
  217. data/lib/active_record/validations/uniqueness.rb +4 -4
  218. data/lib/active_record/version.rb +1 -1
  219. data/lib/active_record.rb +225 -27
  220. data/lib/arel/attributes/attribute.rb +0 -8
  221. data/lib/arel/crud.rb +28 -22
  222. data/lib/arel/delete_manager.rb +18 -4
  223. data/lib/arel/filter_predications.rb +9 -0
  224. data/lib/arel/insert_manager.rb +2 -3
  225. data/lib/arel/nodes/and.rb +4 -0
  226. data/lib/arel/nodes/casted.rb +1 -1
  227. data/lib/arel/nodes/delete_statement.rb +12 -13
  228. data/lib/arel/nodes/filter.rb +10 -0
  229. data/lib/arel/nodes/function.rb +1 -0
  230. data/lib/arel/nodes/insert_statement.rb +2 -2
  231. data/lib/arel/nodes/select_core.rb +2 -2
  232. data/lib/arel/nodes/select_statement.rb +2 -2
  233. data/lib/arel/nodes/update_statement.rb +8 -3
  234. data/lib/arel/nodes.rb +1 -0
  235. data/lib/arel/predications.rb +11 -3
  236. data/lib/arel/select_manager.rb +10 -4
  237. data/lib/arel/table.rb +0 -1
  238. data/lib/arel/tree_manager.rb +0 -12
  239. data/lib/arel/update_manager.rb +18 -4
  240. data/lib/arel/visitors/dot.rb +80 -90
  241. data/lib/arel/visitors/mysql.rb +8 -2
  242. data/lib/arel/visitors/postgresql.rb +0 -10
  243. data/lib/arel/visitors/to_sql.rb +58 -2
  244. data/lib/arel.rb +2 -1
  245. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  246. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  247. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  248. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  249. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  250. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  251. metadata +55 -11
@@ -62,9 +62,9 @@ module ActiveRecord
62
62
  # Active Record callbacks or validations. Though passed values
63
63
  # go through Active Record's type casting and serialization.
64
64
  #
65
- # See <tt>ActiveRecord::Persistence#insert_all</tt> for documentation.
66
- def insert(attributes, returning: nil, unique_by: nil)
67
- insert_all([ attributes ], returning: returning, unique_by: unique_by)
65
+ # See #insert_all for documentation.
66
+ def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
67
+ insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
68
68
  end
69
69
 
70
70
  # Inserts multiple records into the database in a single SQL INSERT
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  # duplicate rows are skipped.
80
80
  # Override with <tt>:unique_by</tt> (see below).
81
81
  #
82
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
82
+ # Returns an ActiveRecord::Result with its contents based on
83
83
  # <tt>:returning</tt> (see below).
84
84
  #
85
85
  # ==== Options
@@ -91,6 +91,9 @@ module ActiveRecord
91
91
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
92
92
  # clause entirely.
93
93
  #
94
+ # You can also pass an SQL string if you need more control on the return values
95
+ # (for example, <tt>returning: "id, name as new_name"</tt>).
96
+ #
94
97
  # [:unique_by]
95
98
  # (PostgreSQL and SQLite only) By default rows are considered to be unique
96
99
  # by every unique index on the table. Any duplicate rows are skipped.
@@ -107,6 +110,17 @@ module ActiveRecord
107
110
  # unique_by: %i[ author_id name ]
108
111
  # unique_by: :index_books_on_isbn
109
112
  #
113
+ # [:record_timestamps]
114
+ # By default, automatic setting of timestamp columns is controlled by
115
+ # the model's <tt>record_timestamps</tt> config, matching typical
116
+ # behavior.
117
+ #
118
+ # To override this and force automatic setting of timestamp columns one
119
+ # way or the other, pass <tt>:record_timestamps</tt>:
120
+ #
121
+ # record_timestamps: true # Always set timestamps automatically
122
+ # record_timestamps: false # Never set timestamps automatically
123
+ #
110
124
  # Because it relies on the index information from the database
111
125
  # <tt>:unique_by</tt> is recommended to be paired with
112
126
  # Active Record's schema_cache.
@@ -120,8 +134,16 @@ module ActiveRecord
120
134
  # { id: 1, title: "Rework", author: "David" },
121
135
  # { id: 1, title: "Eloquent Ruby", author: "Russ" }
122
136
  # ])
123
- def insert_all(attributes, returning: nil, unique_by: nil)
124
- InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by).execute
137
+ #
138
+ # # insert_all works on chained scopes, and you can use create_with
139
+ # # to set default attributes for all inserted records.
140
+ #
141
+ # author.books.create_with(created_at: Time.now).insert_all([
142
+ # { id: 1, title: "Rework" },
143
+ # { id: 2, title: "Eloquent Ruby" }
144
+ # ])
145
+ def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
146
+ InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
125
147
  end
126
148
 
127
149
  # Inserts a single record into the database in a single SQL INSERT
@@ -129,9 +151,9 @@ module ActiveRecord
129
151
  # Active Record callbacks or validations. Though passed values
130
152
  # go through Active Record's type casting and serialization.
131
153
  #
132
- # See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
133
- def insert!(attributes, returning: nil)
134
- insert_all!([ attributes ], returning: returning)
154
+ # See #insert_all! for more.
155
+ def insert!(attributes, returning: nil, record_timestamps: nil)
156
+ insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
135
157
  end
136
158
 
137
159
  # Inserts multiple records into the database in a single SQL INSERT
@@ -145,10 +167,9 @@ module ActiveRecord
145
167
  # Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
146
168
  # unique index on the table. In that case, no rows are inserted.
147
169
  #
148
- # To skip duplicate rows, see <tt>ActiveRecord::Persistence#insert_all</tt>.
149
- # To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
170
+ # To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
150
171
  #
151
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
172
+ # Returns an ActiveRecord::Result with its contents based on
152
173
  # <tt>:returning</tt> (see below).
153
174
  #
154
175
  # ==== Options
@@ -160,6 +181,20 @@ module ActiveRecord
160
181
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
161
182
  # clause entirely.
162
183
  #
184
+ # You can also pass an SQL string if you need more control on the return values
185
+ # (for example, <tt>returning: "id, name as new_name"</tt>).
186
+ #
187
+ # [:record_timestamps]
188
+ # By default, automatic setting of timestamp columns is controlled by
189
+ # the model's <tt>record_timestamps</tt> config, matching typical
190
+ # behavior.
191
+ #
192
+ # To override this and force automatic setting of timestamp columns one
193
+ # way or the other, pass <tt>:record_timestamps</tt>:
194
+ #
195
+ # record_timestamps: true # Always set timestamps automatically
196
+ # record_timestamps: false # Never set timestamps automatically
197
+ #
163
198
  # ==== Examples
164
199
  #
165
200
  # # Insert multiple records
@@ -174,8 +209,8 @@ module ActiveRecord
174
209
  # { id: 1, title: "Rework", author: "David" },
175
210
  # { id: 1, title: "Eloquent Ruby", author: "Russ" }
176
211
  # ])
177
- def insert_all!(attributes, returning: nil)
178
- InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning).execute
212
+ def insert_all!(attributes, returning: nil, record_timestamps: nil)
213
+ InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps).execute
179
214
  end
180
215
 
181
216
  # Updates or inserts (upserts) a single record into the database in a
@@ -183,9 +218,9 @@ module ActiveRecord
183
218
  # it trigger Active Record callbacks or validations. Though passed values
184
219
  # go through Active Record's type casting and serialization.
185
220
  #
186
- # See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
187
- def upsert(attributes, returning: nil, unique_by: nil)
188
- upsert_all([ attributes ], returning: returning, unique_by: unique_by)
221
+ # See #upsert_all for documentation.
222
+ def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil, record_timestamps: nil)
223
+ upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
189
224
  end
190
225
 
191
226
  # Updates or inserts (upserts) multiple records into the database in a
@@ -196,9 +231,13 @@ module ActiveRecord
196
231
  # The +attributes+ parameter is an Array of Hashes. Every Hash determines
197
232
  # the attributes for a single row and must have the same keys.
198
233
  #
199
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
234
+ # Returns an ActiveRecord::Result with its contents based on
200
235
  # <tt>:returning</tt> (see below).
201
236
  #
237
+ # By default, +upsert_all+ will update all the columns that can be updated when
238
+ # there is a conflict. These are all the columns except primary keys, read-only
239
+ # columns, and columns covered by the optional +unique_by+.
240
+ #
202
241
  # ==== Options
203
242
  #
204
243
  # [:returning]
@@ -208,6 +247,9 @@ module ActiveRecord
208
247
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
209
248
  # clause entirely.
210
249
  #
250
+ # You can also pass an SQL string if you need more control on the return values
251
+ # (for example, <tt>returning: "id, name as new_name"</tt>).
252
+ #
211
253
  # [:unique_by]
212
254
  # (PostgreSQL and SQLite only) By default rows are considered to be unique
213
255
  # by every unique index on the table. Any duplicate rows are skipped.
@@ -228,6 +270,54 @@ module ActiveRecord
228
270
  # <tt>:unique_by</tt> is recommended to be paired with
229
271
  # Active Record's schema_cache.
230
272
  #
273
+ # [:on_duplicate]
274
+ # Configure the SQL update sentence that will be used in case of conflict.
275
+ #
276
+ # NOTE: If you use this option you must provide all the columns you want to update
277
+ # by yourself.
278
+ #
279
+ # Example:
280
+ #
281
+ # Commodity.upsert_all(
282
+ # [
283
+ # { id: 2, name: "Copper", price: 4.84 },
284
+ # { id: 4, name: "Gold", price: 1380.87 },
285
+ # { id: 6, name: "Aluminium", price: 0.35 }
286
+ # ],
287
+ # on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
288
+ # )
289
+ #
290
+ # See the related +:update_only+ option. Both options can't be used at the same time.
291
+ #
292
+ # [:update_only]
293
+ # Provide a list of column names that will be updated in case of conflict. If not provided,
294
+ # +upsert_all+ will update all the columns that can be updated. These are all the columns
295
+ # except primary keys, read-only columns, and columns covered by the optional +unique_by+
296
+ #
297
+ # Example:
298
+ #
299
+ # Commodity.upsert_all(
300
+ # [
301
+ # { id: 2, name: "Copper", price: 4.84 },
302
+ # { id: 4, name: "Gold", price: 1380.87 },
303
+ # { id: 6, name: "Aluminium", price: 0.35 }
304
+ # ],
305
+ # update_only: [:price] # Only prices will be updated
306
+ # )
307
+ #
308
+ # See the related +:on_duplicate+ option. Both options can't be used at the same time.
309
+ #
310
+ # [:record_timestamps]
311
+ # By default, automatic setting of timestamp columns is controlled by
312
+ # the model's <tt>record_timestamps</tt> config, matching typical
313
+ # behavior.
314
+ #
315
+ # To override this and force automatic setting of timestamp columns one
316
+ # way or the other, pass <tt>:record_timestamps</tt>:
317
+ #
318
+ # record_timestamps: true # Always set timestamps automatically
319
+ # record_timestamps: false # Never set timestamps automatically
320
+ #
231
321
  # ==== Examples
232
322
  #
233
323
  # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
@@ -239,8 +329,8 @@ module ActiveRecord
239
329
  # ], unique_by: :isbn)
240
330
  #
241
331
  # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
242
- def upsert_all(attributes, returning: nil, unique_by: nil)
243
- InsertAll.new(self, attributes, on_duplicate: :update, returning: returning, unique_by: unique_by).execute
332
+ def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
333
+ InsertAll.new(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
244
334
  end
245
335
 
246
336
  # Given an attributes hash, +instantiate+ returns a new instance of
@@ -264,6 +354,7 @@ module ActiveRecord
264
354
  # ==== Parameters
265
355
  #
266
356
  # * +id+ - This should be the id or an array of ids to be updated.
357
+ # Optional argument, defaults to all records in the relation.
267
358
  # * +attributes+ - This should be a hash of attributes or an array of hashes.
268
359
  #
269
360
  # ==== Examples
@@ -286,6 +377,11 @@ module ActiveRecord
286
377
  # for updating all records in a single query.
287
378
  def update(id = :all, attributes)
288
379
  if id.is_a?(Array)
380
+ if id.any?(ActiveRecord::Base)
381
+ raise ArgumentError,
382
+ "You are passing an array of ActiveRecord::Base instances to `update`. " \
383
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
384
+ end
289
385
  id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
290
386
  object.update(attributes[idx])
291
387
  }
@@ -303,6 +399,32 @@ module ActiveRecord
303
399
  end
304
400
  end
305
401
 
402
+ # Updates the object (or multiple objects) just like #update but calls #update! instead
403
+ # of +update+, so an exception is raised if the record is invalid and saving will fail.
404
+ def update!(id = :all, attributes)
405
+ if id.is_a?(Array)
406
+ if id.any?(ActiveRecord::Base)
407
+ raise ArgumentError,
408
+ "You are passing an array of ActiveRecord::Base instances to `update!`. " \
409
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
410
+ end
411
+ id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
412
+ object.update!(attributes[idx])
413
+ }
414
+ elsif id == :all
415
+ all.each { |record| record.update!(attributes) }
416
+ else
417
+ if ActiveRecord::Base === id
418
+ raise ArgumentError,
419
+ "You are passing an instance of ActiveRecord::Base to `update!`. " \
420
+ "Please pass the id of the object by calling `.id`."
421
+ end
422
+ object = find(id)
423
+ object.update!(attributes)
424
+ object
425
+ end
426
+ end
427
+
306
428
  # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
307
429
  # therefore all callbacks and filters are fired off before the object is deleted. This method is
308
430
  # less efficient than #delete but allows cleanup methods and other actions to be run.
@@ -356,40 +478,52 @@ module ActiveRecord
356
478
  primary_key = self.primary_key
357
479
  primary_key_value = nil
358
480
 
359
- if primary_key && Hash === values
360
- primary_key_value = values[primary_key]
361
-
362
- if !primary_key_value && prefetch_primary_key?
481
+ if prefetch_primary_key? && primary_key
482
+ values[primary_key] ||= begin
363
483
  primary_key_value = next_sequence_value
364
- values[primary_key] = primary_key_value
484
+ _default_attributes[primary_key].with_cast_value(primary_key_value)
365
485
  end
366
486
  end
367
487
 
488
+ im = Arel::InsertManager.new(arel_table)
489
+
368
490
  if values.empty?
369
- im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
370
- im.into arel_table
491
+ im.insert(connection.empty_insert_statement_value(primary_key))
371
492
  else
372
- im = arel_table.compile_insert(_substitute_values(values))
493
+ im.insert(values.transform_keys { |name| arel_table[name] })
373
494
  end
374
495
 
375
496
  connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
376
497
  end
377
498
 
378
499
  def _update_record(values, constraints) # :nodoc:
379
- constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
500
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
501
+
502
+ default_constraint = build_default_constraint
503
+ constraints << default_constraint if default_constraint
380
504
 
381
- um = arel_table.where(
382
- constraints.reduce(&:and)
383
- ).compile_update(_substitute_values(values), primary_key)
505
+ if current_scope = self.global_current_scope
506
+ constraints << current_scope.where_clause.ast
507
+ end
508
+
509
+ um = Arel::UpdateManager.new(arel_table)
510
+ um.set(values.transform_keys { |name| arel_table[name] })
511
+ um.wheres = constraints
384
512
 
385
513
  connection.update(um, "#{self} Update")
386
514
  end
387
515
 
388
516
  def _delete_record(constraints) # :nodoc:
389
- constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
517
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
518
+
519
+ default_constraint = build_default_constraint
520
+ constraints << default_constraint if default_constraint
521
+
522
+ if current_scope = self.global_current_scope
523
+ constraints << current_scope.where_clause.ast
524
+ end
390
525
 
391
- dm = Arel::DeleteManager.new
392
- dm.from(arel_table)
526
+ dm = Arel::DeleteManager.new(arel_table)
393
527
  dm.wheres = constraints
394
528
 
395
529
  connection.delete(dm, "#{self} Destroy")
@@ -412,12 +546,14 @@ module ActiveRecord
412
546
  self
413
547
  end
414
548
 
415
- def _substitute_values(values)
416
- values.map do |name, value|
417
- attr = arel_table[name]
418
- bind = predicate_builder.build_bind_attribute(attr.name, value)
419
- [attr, bind]
420
- end
549
+ # Called by +_update_record+ and +_delete_record+
550
+ # to build `where` clause from default scopes.
551
+ # Skips empty scopes.
552
+ def build_default_constraint
553
+ return unless default_scopes?(all_queries: true)
554
+
555
+ default_where_clause = default_scoped(all_queries: true).where_clause
556
+ default_where_clause.ast unless default_where_clause.empty?
421
557
  end
422
558
  end
423
559
 
@@ -428,12 +564,17 @@ module ActiveRecord
428
564
  end
429
565
 
430
566
  # Returns true if this object was just created -- that is, prior to the last
431
- # save, the object didn't exist in the database and new_record? would have
567
+ # update or delete, the object didn't exist in the database and new_record? would have
432
568
  # returned true.
433
569
  def previously_new_record?
434
570
  @previously_new_record
435
571
  end
436
572
 
573
+ # Returns true if this object was previously persisted but now it has been deleted.
574
+ def previously_persisted?
575
+ !new_record? && destroyed?
576
+ end
577
+
437
578
  # Returns true if this object has been destroyed, otherwise returns false.
438
579
  def destroyed?
439
580
  @destroyed
@@ -522,6 +663,7 @@ module ActiveRecord
522
663
  def delete
523
664
  _delete_row if persisted?
524
665
  @destroyed = true
666
+ @previously_new_record = false
525
667
  freeze
526
668
  end
527
669
 
@@ -541,6 +683,7 @@ module ActiveRecord
541
683
  true
542
684
  end
543
685
  @destroyed = true
686
+ @previously_new_record = false
544
687
  freeze
545
688
  end
546
689
 
@@ -556,17 +699,17 @@ module ActiveRecord
556
699
  end
557
700
 
558
701
  # Returns an instance of the specified +klass+ with the attributes of the
559
- # current record. This is mostly useful in relation to single-table
560
- # inheritance structures where you want a subclass to appear as the
702
+ # current record. This is mostly useful in relation to single table
703
+ # inheritance (STI) structures where you want a subclass to appear as the
561
704
  # superclass. This can be used along with record identification in
562
705
  # Action Pack to allow, say, <tt>Client < Company</tt> to do something
563
706
  # like render <tt>partial: @client.becomes(Company)</tt> to render that
564
707
  # instance using the companies/company partial instead of clients/client.
565
708
  #
566
709
  # Note: The new instance will share a link to the same attributes as the original class.
567
- # Therefore the sti column value will still be the same.
710
+ # Therefore the STI column value will still be the same.
568
711
  # Any change to the attributes on either instance will affect both instances.
569
- # If you want to change the sti column as well, use #becomes! instead.
712
+ # If you want to change the STI column as well, use #becomes! instead.
570
713
  def becomes(klass)
571
714
  became = klass.allocate
572
715
 
@@ -581,11 +724,11 @@ module ActiveRecord
581
724
  became
582
725
  end
583
726
 
584
- # Wrapper around #becomes that also changes the instance's sti column value.
727
+ # Wrapper around #becomes that also changes the instance's STI column value.
585
728
  # This is especially useful if you want to persist the changed class in your
586
729
  # database.
587
730
  #
588
- # Note: The old instance's sti column value will be changed too, as both objects
731
+ # Note: The old instance's STI column value will be changed too, as both objects
589
732
  # share the same set of attributes.
590
733
  def becomes!(klass)
591
734
  became = becomes(klass)
@@ -664,6 +807,7 @@ module ActiveRecord
664
807
  def update_columns(attributes)
665
808
  raise ActiveRecordError, "cannot update a new record" if new_record?
666
809
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
810
+ _raise_readonly_record_error if readonly?
667
811
 
668
812
  attributes = attributes.transform_keys do |key|
669
813
  name = key.to_s
@@ -671,14 +815,15 @@ module ActiveRecord
671
815
  verify_readonly_attribute(name) || name
672
816
  end
673
817
 
674
- id_in_database = self.id_in_database
675
- attributes.each do |k, v|
676
- write_attribute_without_type_cast(k, v)
818
+ update_constraints = _query_constraints_hash
819
+ attributes = attributes.each_with_object({}) do |(k, v), h|
820
+ h[k] = @attributes.write_cast_value(k, v)
821
+ clear_attribute_change(k)
677
822
  end
678
823
 
679
824
  affected_rows = self.class._update_record(
680
825
  attributes,
681
- @primary_key => id_in_database
826
+ update_constraints
682
827
  )
683
828
 
684
829
  affected_rows == 1
@@ -800,13 +945,13 @@ module ActiveRecord
800
945
  def reload(options = nil)
801
946
  self.class.connection.clear_query_cache
802
947
 
803
- fresh_object =
804
- if options && options[:lock]
805
- self.class.unscoped { self.class.lock(options[:lock]).find(id) }
806
- else
807
- self.class.unscoped { self.class.find(id) }
808
- end
948
+ fresh_object = if apply_scoping?(options)
949
+ _find_record(options)
950
+ else
951
+ self.class.unscoped { _find_record(options) }
952
+ end
809
953
 
954
+ @association_cache = fresh_object.instance_variable_get(:@association_cache)
810
955
  @attributes = fresh_object.instance_variable_get(:@attributes)
811
956
  @new_record = false
812
957
  @previously_new_record = false
@@ -849,6 +994,7 @@ module ActiveRecord
849
994
  #
850
995
  def touch(*names, time: nil)
851
996
  _raise_record_not_touched_error unless persisted?
997
+ _raise_readonly_record_error if readonly?
852
998
 
853
999
  attribute_names = timestamp_attributes_for_update_in_model
854
1000
  attribute_names |= names.map! do |name|
@@ -865,6 +1011,29 @@ module ActiveRecord
865
1011
  end
866
1012
 
867
1013
  private
1014
+ def strict_loaded_associations
1015
+ @association_cache.find_all do |_, assoc|
1016
+ assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
1017
+ end.map(&:first)
1018
+ end
1019
+
1020
+ def _find_record(options)
1021
+ if options && options[:lock]
1022
+ self.class.preload(strict_loaded_associations).lock(options[:lock]).find(id)
1023
+ else
1024
+ self.class.preload(strict_loaded_associations).find(id)
1025
+ end
1026
+ end
1027
+
1028
+ def apply_scoping?(options)
1029
+ !(options && options[:unscoped]) &&
1030
+ (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
1031
+ end
1032
+
1033
+ def _query_constraints_hash
1034
+ { @primary_key => id_in_database }
1035
+ end
1036
+
868
1037
  # A hook to be overridden by association modules.
869
1038
  def destroy_associations
870
1039
  end
@@ -874,7 +1043,7 @@ module ActiveRecord
874
1043
  end
875
1044
 
876
1045
  def _delete_row
877
- self.class._delete_record(@primary_key => id_in_database)
1046
+ self.class._delete_record(_query_constraints_hash)
878
1047
  end
879
1048
 
880
1049
  def _touch_row(attribute_names, time)
@@ -890,7 +1059,7 @@ module ActiveRecord
890
1059
  def _update_row(attribute_names, attempted_action = "update")
891
1060
  self.class._update_record(
892
1061
  attributes_with_values(attribute_names),
893
- @primary_key => id_in_database
1062
+ _query_constraints_hash
894
1063
  )
895
1064
  end
896
1065
 
@@ -946,7 +1115,8 @@ module ActiveRecord
946
1115
 
947
1116
  def _raise_record_not_destroyed
948
1117
  @_association_destroy_exception ||= nil
949
- raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
1118
+ key = self.class.primary_key
1119
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{send(key)}", self)
950
1120
  ensure
951
1121
  @_association_destroy_exception = nil
952
1122
  end
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  def self.run
29
29
  pools = []
30
30
 
31
- if ActiveRecord::Base.legacy_connection_handling
31
+ if ActiveRecord.legacy_connection_handling
32
32
  ActiveRecord::Base.connection_handlers.each do |key, handler|
33
33
  pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
34
34
  end
@@ -42,7 +42,7 @@ module ActiveRecord
42
42
  def self.complete(pools)
43
43
  pools.each { |pool| pool.disable_query_cache! }
44
44
 
45
- if ActiveRecord::Base.legacy_connection_handling
45
+ if ActiveRecord.legacy_connection_handling
46
46
  ActiveRecord::Base.connection_handlers.each do |_, handler|
47
47
  handler.connection_pool_list.each do |pool|
48
48
  pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?