activerecord 7.1.5.1 → 8.0.2

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +369 -2484
  3. data/README.rdoc +15 -15
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +2 -1
  6. data/lib/active_record/associations/alias_tracker.rb +31 -23
  7. data/lib/active_record/associations/association.rb +43 -12
  8. data/lib/active_record/associations/belongs_to_association.rb +21 -8
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/association.rb +7 -6
  11. data/lib/active_record/associations/builder/belongs_to.rb +1 -0
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  13. data/lib/active_record/associations/builder/has_many.rb +3 -4
  14. data/lib/active_record/associations/builder/has_one.rb +3 -4
  15. data/lib/active_record/associations/collection_association.rb +17 -9
  16. data/lib/active_record/associations/collection_proxy.rb +14 -1
  17. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  18. data/lib/active_record/associations/errors.rb +265 -0
  19. data/lib/active_record/associations/has_many_association.rb +1 -1
  20. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  21. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  22. data/lib/active_record/associations/nested_error.rb +47 -0
  23. data/lib/active_record/associations/preloader/association.rb +4 -3
  24. data/lib/active_record/associations/preloader/branch.rb +7 -1
  25. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  26. data/lib/active_record/associations/singular_association.rb +14 -3
  27. data/lib/active_record/associations/through_association.rb +1 -1
  28. data/lib/active_record/associations.rb +92 -295
  29. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  30. data/lib/active_record/attribute_assignment.rb +0 -2
  31. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  32. data/lib/active_record/attribute_methods/primary_key.rb +25 -61
  33. data/lib/active_record/attribute_methods/read.rb +1 -13
  34. data/lib/active_record/attribute_methods/serialization.rb +4 -24
  35. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
  36. data/lib/active_record/attribute_methods.rb +71 -75
  37. data/lib/active_record/attributes.rb +63 -49
  38. data/lib/active_record/autosave_association.rb +92 -57
  39. data/lib/active_record/base.rb +2 -3
  40. data/lib/active_record/callbacks.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
  42. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  43. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
  44. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
  45. data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
  46. data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
  47. data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
  48. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
  49. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
  50. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
  51. data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
  52. data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
  53. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
  54. data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
  55. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
  56. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  57. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
  58. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
  59. data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
  60. data/lib/active_record/connection_adapters/pool_config.rb +14 -13
  61. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
  62. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  63. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  64. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  66. data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
  67. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  68. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
  69. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
  70. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
  71. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
  72. data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
  73. data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
  74. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  75. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
  76. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
  77. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
  78. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  79. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
  80. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
  81. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
  82. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  83. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
  84. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
  85. data/lib/active_record/connection_adapters.rb +65 -0
  86. data/lib/active_record/connection_handling.rb +74 -37
  87. data/lib/active_record/core.rb +132 -51
  88. data/lib/active_record/counter_cache.rb +19 -10
  89. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
  90. data/lib/active_record/database_configurations/database_config.rb +23 -4
  91. data/lib/active_record/database_configurations/hash_config.rb +46 -34
  92. data/lib/active_record/database_configurations/url_config.rb +20 -1
  93. data/lib/active_record/database_configurations.rb +1 -1
  94. data/lib/active_record/delegated_type.rb +41 -17
  95. data/lib/active_record/dynamic_matchers.rb +2 -2
  96. data/lib/active_record/encryption/config.rb +3 -1
  97. data/lib/active_record/encryption/encryptable_record.rb +7 -7
  98. data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
  99. data/lib/active_record/encryption/encryptor.rb +28 -6
  100. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  101. data/lib/active_record/encryption/key_provider.rb +1 -1
  102. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  103. data/lib/active_record/encryption/message_serializer.rb +4 -0
  104. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  105. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  106. data/lib/active_record/encryption/scheme.rb +8 -1
  107. data/lib/active_record/enum.rb +20 -16
  108. data/lib/active_record/errors.rb +54 -20
  109. data/lib/active_record/explain.rb +13 -24
  110. data/lib/active_record/fixtures.rb +37 -33
  111. data/lib/active_record/future_result.rb +21 -13
  112. data/lib/active_record/gem_version.rb +4 -4
  113. data/lib/active_record/inheritance.rb +4 -2
  114. data/lib/active_record/insert_all.rb +19 -16
  115. data/lib/active_record/integration.rb +4 -1
  116. data/lib/active_record/internal_metadata.rb +48 -34
  117. data/lib/active_record/locking/optimistic.rb +8 -7
  118. data/lib/active_record/log_subscriber.rb +5 -32
  119. data/lib/active_record/message_pack.rb +1 -1
  120. data/lib/active_record/migration/command_recorder.rb +33 -14
  121. data/lib/active_record/migration/compatibility.rb +8 -3
  122. data/lib/active_record/migration/default_strategy.rb +4 -5
  123. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  124. data/lib/active_record/migration.rb +104 -98
  125. data/lib/active_record/model_schema.rb +32 -70
  126. data/lib/active_record/nested_attributes.rb +15 -9
  127. data/lib/active_record/normalization.rb +3 -7
  128. data/lib/active_record/persistence.rb +127 -451
  129. data/lib/active_record/query_cache.rb +19 -8
  130. data/lib/active_record/query_logs.rb +104 -37
  131. data/lib/active_record/query_logs_formatter.rb +17 -28
  132. data/lib/active_record/querying.rb +24 -12
  133. data/lib/active_record/railtie.rb +26 -68
  134. data/lib/active_record/railties/controller_runtime.rb +13 -4
  135. data/lib/active_record/railties/databases.rake +43 -61
  136. data/lib/active_record/reflection.rb +112 -53
  137. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  138. data/lib/active_record/relation/batches.rb +138 -72
  139. data/lib/active_record/relation/calculations.rb +122 -82
  140. data/lib/active_record/relation/delegation.rb +30 -22
  141. data/lib/active_record/relation/finder_methods.rb +32 -18
  142. data/lib/active_record/relation/merger.rb +12 -14
  143. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  144. data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
  145. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  146. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  147. data/lib/active_record/relation/predicate_builder.rb +16 -3
  148. data/lib/active_record/relation/query_attribute.rb +1 -1
  149. data/lib/active_record/relation/query_methods.rb +317 -101
  150. data/lib/active_record/relation/spawn_methods.rb +3 -19
  151. data/lib/active_record/relation/where_clause.rb +7 -19
  152. data/lib/active_record/relation.rb +561 -119
  153. data/lib/active_record/result.rb +95 -46
  154. data/lib/active_record/runtime_registry.rb +39 -0
  155. data/lib/active_record/sanitization.rb +31 -25
  156. data/lib/active_record/schema.rb +8 -6
  157. data/lib/active_record/schema_dumper.rb +53 -20
  158. data/lib/active_record/schema_migration.rb +31 -14
  159. data/lib/active_record/scoping/named.rb +6 -2
  160. data/lib/active_record/signed_id.rb +24 -4
  161. data/lib/active_record/statement_cache.rb +19 -19
  162. data/lib/active_record/store.rb +7 -3
  163. data/lib/active_record/table_metadata.rb +2 -13
  164. data/lib/active_record/tasks/database_tasks.rb +87 -58
  165. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
  166. data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
  167. data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
  168. data/lib/active_record/test_fixtures.rb +98 -89
  169. data/lib/active_record/testing/query_assertions.rb +121 -0
  170. data/lib/active_record/timestamp.rb +2 -2
  171. data/lib/active_record/token_for.rb +22 -12
  172. data/lib/active_record/touch_later.rb +1 -1
  173. data/lib/active_record/transaction.rb +132 -0
  174. data/lib/active_record/transactions.rb +72 -17
  175. data/lib/active_record/translation.rb +0 -2
  176. data/lib/active_record/type/serialized.rb +1 -3
  177. data/lib/active_record/type_caster/connection.rb +4 -4
  178. data/lib/active_record/validations/associated.rb +9 -3
  179. data/lib/active_record/validations/uniqueness.rb +23 -18
  180. data/lib/active_record/validations.rb +4 -1
  181. data/lib/active_record.rb +138 -57
  182. data/lib/arel/alias_predication.rb +1 -1
  183. data/lib/arel/collectors/bind.rb +4 -2
  184. data/lib/arel/collectors/composite.rb +7 -0
  185. data/lib/arel/collectors/sql_string.rb +2 -2
  186. data/lib/arel/collectors/substitute_binds.rb +3 -3
  187. data/lib/arel/nodes/binary.rb +1 -7
  188. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  189. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  190. data/lib/arel/nodes/node.rb +5 -4
  191. data/lib/arel/nodes/sql_literal.rb +8 -1
  192. data/lib/arel/nodes.rb +2 -2
  193. data/lib/arel/predications.rb +1 -1
  194. data/lib/arel/select_manager.rb +1 -1
  195. data/lib/arel/table.rb +3 -7
  196. data/lib/arel/tree_manager.rb +3 -2
  197. data/lib/arel/update_manager.rb +2 -1
  198. data/lib/arel/visitors/dot.rb +1 -0
  199. data/lib/arel/visitors/mysql.rb +9 -4
  200. data/lib/arel/visitors/postgresql.rb +1 -12
  201. data/lib/arel/visitors/sqlite.rb +25 -0
  202. data/lib/arel/visitors/to_sql.rb +29 -16
  203. data/lib/arel.rb +7 -3
  204. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  205. metadata +18 -16
  206. data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -87,282 +87,6 @@ module ActiveRecord
87
87
  end
88
88
  end
89
89
 
90
- # Inserts a single record into the database in a single SQL INSERT
91
- # statement. It does not instantiate any models nor does it trigger
92
- # Active Record callbacks or validations. Though passed values
93
- # go through Active Record's type casting and serialization.
94
- #
95
- # See #insert_all for documentation.
96
- def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
97
- insert_all([ attributes ], returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
98
- end
99
-
100
- # Inserts multiple records into the database in a single SQL INSERT
101
- # statement. It does not instantiate any models nor does it trigger
102
- # Active Record callbacks or validations. Though passed values
103
- # go through Active Record's type casting and serialization.
104
- #
105
- # The +attributes+ parameter is an Array of Hashes. Every Hash determines
106
- # the attributes for a single row and must have the same keys.
107
- #
108
- # Rows are considered to be unique by every unique index on the table. Any
109
- # duplicate rows are skipped.
110
- # Override with <tt>:unique_by</tt> (see below).
111
- #
112
- # Returns an ActiveRecord::Result with its contents based on
113
- # <tt>:returning</tt> (see below).
114
- #
115
- # ==== Options
116
- #
117
- # [:returning]
118
- # (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
119
- # inserted records, which by default is the primary key.
120
- # Pass <tt>returning: %w[ id name ]</tt> for both id and name
121
- # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
122
- # clause entirely.
123
- #
124
- # You can also pass an SQL string if you need more control on the return values
125
- # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
126
- #
127
- # [:unique_by]
128
- # (PostgreSQL and SQLite only) By default rows are considered to be unique
129
- # by every unique index on the table. Any duplicate rows are skipped.
130
- #
131
- # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
132
- #
133
- # Consider a Book model where no duplicate ISBNs make sense, but if any
134
- # row has an existing id, or is not unique by another unique index,
135
- # ActiveRecord::RecordNotUnique is raised.
136
- #
137
- # Unique indexes can be identified by columns or name:
138
- #
139
- # unique_by: :isbn
140
- # unique_by: %i[ author_id name ]
141
- # unique_by: :index_books_on_isbn
142
- #
143
- # [:record_timestamps]
144
- # By default, automatic setting of timestamp columns is controlled by
145
- # the model's <tt>record_timestamps</tt> config, matching typical
146
- # behavior.
147
- #
148
- # To override this and force automatic setting of timestamp columns one
149
- # way or the other, pass <tt>:record_timestamps</tt>:
150
- #
151
- # record_timestamps: true # Always set timestamps automatically
152
- # record_timestamps: false # Never set timestamps automatically
153
- #
154
- # Because it relies on the index information from the database
155
- # <tt>:unique_by</tt> is recommended to be paired with
156
- # Active Record's schema_cache.
157
- #
158
- # ==== Example
159
- #
160
- # # Insert records and skip inserting any duplicates.
161
- # # Here "Eloquent Ruby" is skipped because its id is not unique.
162
- #
163
- # Book.insert_all([
164
- # { id: 1, title: "Rework", author: "David" },
165
- # { id: 1, title: "Eloquent Ruby", author: "Russ" }
166
- # ])
167
- #
168
- # # insert_all works on chained scopes, and you can use create_with
169
- # # to set default attributes for all inserted records.
170
- #
171
- # author.books.create_with(created_at: Time.now).insert_all([
172
- # { id: 1, title: "Rework" },
173
- # { id: 2, title: "Eloquent Ruby" }
174
- # ])
175
- def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil)
176
- InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
177
- end
178
-
179
- # Inserts a single record into the database in a single SQL INSERT
180
- # statement. It does not instantiate any models nor does it trigger
181
- # Active Record callbacks or validations. Though passed values
182
- # go through Active Record's type casting and serialization.
183
- #
184
- # See #insert_all! for more.
185
- def insert!(attributes, returning: nil, record_timestamps: nil)
186
- insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
187
- end
188
-
189
- # Inserts multiple records into the database in a single SQL INSERT
190
- # statement. It does not instantiate any models nor does it trigger
191
- # Active Record callbacks or validations. Though passed values
192
- # go through Active Record's type casting and serialization.
193
- #
194
- # The +attributes+ parameter is an Array of Hashes. Every Hash determines
195
- # the attributes for a single row and must have the same keys.
196
- #
197
- # Raises ActiveRecord::RecordNotUnique if any rows violate a
198
- # unique index on the table. In that case, no rows are inserted.
199
- #
200
- # To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
201
- #
202
- # Returns an ActiveRecord::Result with its contents based on
203
- # <tt>:returning</tt> (see below).
204
- #
205
- # ==== Options
206
- #
207
- # [:returning]
208
- # (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
209
- # inserted records, which by default is the primary key.
210
- # Pass <tt>returning: %w[ id name ]</tt> for both id and name
211
- # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
212
- # clause entirely.
213
- #
214
- # You can also pass an SQL string if you need more control on the return values
215
- # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
216
- #
217
- # [:record_timestamps]
218
- # By default, automatic setting of timestamp columns is controlled by
219
- # the model's <tt>record_timestamps</tt> config, matching typical
220
- # behavior.
221
- #
222
- # To override this and force automatic setting of timestamp columns one
223
- # way or the other, pass <tt>:record_timestamps</tt>:
224
- #
225
- # record_timestamps: true # Always set timestamps automatically
226
- # record_timestamps: false # Never set timestamps automatically
227
- #
228
- # ==== Examples
229
- #
230
- # # Insert multiple records
231
- # Book.insert_all!([
232
- # { title: "Rework", author: "David" },
233
- # { title: "Eloquent Ruby", author: "Russ" }
234
- # ])
235
- #
236
- # # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
237
- # # does not have a unique id.
238
- # Book.insert_all!([
239
- # { id: 1, title: "Rework", author: "David" },
240
- # { id: 1, title: "Eloquent Ruby", author: "Russ" }
241
- # ])
242
- def insert_all!(attributes, returning: nil, record_timestamps: nil)
243
- InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps).execute
244
- end
245
-
246
- # Updates or inserts (upserts) a single record into the database in a
247
- # single SQL INSERT statement. It does not instantiate any models nor does
248
- # it trigger Active Record callbacks or validations. Though passed values
249
- # go through Active Record's type casting and serialization.
250
- #
251
- # See #upsert_all for documentation.
252
- def upsert(attributes, **kwargs)
253
- upsert_all([ attributes ], **kwargs)
254
- end
255
-
256
- # Updates or inserts (upserts) multiple records into the database in a
257
- # single SQL INSERT statement. It does not instantiate any models nor does
258
- # it trigger Active Record callbacks or validations. Though passed values
259
- # go through Active Record's type casting and serialization.
260
- #
261
- # The +attributes+ parameter is an Array of Hashes. Every Hash determines
262
- # the attributes for a single row and must have the same keys.
263
- #
264
- # Returns an ActiveRecord::Result with its contents based on
265
- # <tt>:returning</tt> (see below).
266
- #
267
- # By default, +upsert_all+ will update all the columns that can be updated when
268
- # there is a conflict. These are all the columns except primary keys, read-only
269
- # columns, and columns covered by the optional +unique_by+.
270
- #
271
- # ==== Options
272
- #
273
- # [:returning]
274
- # (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
275
- # inserted records, which by default is the primary key.
276
- # Pass <tt>returning: %w[ id name ]</tt> for both id and name
277
- # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
278
- # clause entirely.
279
- #
280
- # You can also pass an SQL string if you need more control on the return values
281
- # (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
282
- #
283
- # [:unique_by]
284
- # (PostgreSQL and SQLite only) By default rows are considered to be unique
285
- # by every unique index on the table. Any duplicate rows are skipped.
286
- #
287
- # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
288
- #
289
- # Consider a Book model where no duplicate ISBNs make sense, but if any
290
- # row has an existing id, or is not unique by another unique index,
291
- # ActiveRecord::RecordNotUnique is raised.
292
- #
293
- # Unique indexes can be identified by columns or name:
294
- #
295
- # unique_by: :isbn
296
- # unique_by: %i[ author_id name ]
297
- # unique_by: :index_books_on_isbn
298
- #
299
- # Because it relies on the index information from the database
300
- # <tt>:unique_by</tt> is recommended to be paired with
301
- # Active Record's schema_cache.
302
- #
303
- # [:on_duplicate]
304
- # Configure the SQL update sentence that will be used in case of conflict.
305
- #
306
- # NOTE: If you use this option you must provide all the columns you want to update
307
- # by yourself.
308
- #
309
- # Example:
310
- #
311
- # Commodity.upsert_all(
312
- # [
313
- # { id: 2, name: "Copper", price: 4.84 },
314
- # { id: 4, name: "Gold", price: 1380.87 },
315
- # { id: 6, name: "Aluminium", price: 0.35 }
316
- # ],
317
- # on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
318
- # )
319
- #
320
- # See the related +:update_only+ option. Both options can't be used at the same time.
321
- #
322
- # [:update_only]
323
- # Provide a list of column names that will be updated in case of conflict. If not provided,
324
- # +upsert_all+ will update all the columns that can be updated. These are all the columns
325
- # except primary keys, read-only columns, and columns covered by the optional +unique_by+
326
- #
327
- # Example:
328
- #
329
- # Commodity.upsert_all(
330
- # [
331
- # { id: 2, name: "Copper", price: 4.84 },
332
- # { id: 4, name: "Gold", price: 1380.87 },
333
- # { id: 6, name: "Aluminium", price: 0.35 }
334
- # ],
335
- # update_only: [:price] # Only prices will be updated
336
- # )
337
- #
338
- # See the related +:on_duplicate+ option. Both options can't be used at the same time.
339
- #
340
- # [:record_timestamps]
341
- # By default, automatic setting of timestamp columns is controlled by
342
- # the model's <tt>record_timestamps</tt> config, matching typical
343
- # behavior.
344
- #
345
- # To override this and force automatic setting of timestamp columns one
346
- # way or the other, pass <tt>:record_timestamps</tt>:
347
- #
348
- # record_timestamps: true # Always set timestamps automatically
349
- # record_timestamps: false # Never set timestamps automatically
350
- #
351
- # ==== Examples
352
- #
353
- # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
354
- # # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
355
- #
356
- # Book.upsert_all([
357
- # { title: "Rework", author: "David", isbn: "1" },
358
- # { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
359
- # ], unique_by: :isbn)
360
- #
361
- # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
362
- def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
363
- InsertAll.new(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
364
- end
365
-
366
90
  # Given an attributes hash, +instantiate+ returns a new instance of
367
91
  # the appropriate class. Accepts only keys as strings.
368
92
  #
@@ -511,62 +235,7 @@ module ActiveRecord
511
235
  @composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
512
236
  end
513
237
 
514
- # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
515
- # therefore all callbacks and filters are fired off before the object is deleted. This method is
516
- # less efficient than #delete but allows cleanup methods and other actions to be run.
517
- #
518
- # This essentially finds the object (or multiple objects) with the given id, creates a new object
519
- # from the attributes, and then calls destroy on it.
520
- #
521
- # ==== Parameters
522
- #
523
- # * +id+ - This should be the id or an array of ids to be destroyed.
524
- #
525
- # ==== Examples
526
- #
527
- # # Destroy a single object
528
- # Todo.destroy(1)
529
- #
530
- # # Destroy multiple objects
531
- # todos = [1,2,3]
532
- # Todo.destroy(todos)
533
- def destroy(id)
534
- multiple_ids = if composite_primary_key?
535
- id.first.is_a?(Array)
536
- else
537
- id.is_a?(Array)
538
- end
539
-
540
- if multiple_ids
541
- find(id).each(&:destroy)
542
- else
543
- find(id).destroy
544
- end
545
- end
546
-
547
- # Deletes the row with a primary key matching the +id+ argument, using an
548
- # SQL +DELETE+ statement, and returns the number of rows deleted. Active
549
- # Record objects are not instantiated, so the object's callbacks are not
550
- # executed, including any <tt>:dependent</tt> association options.
551
- #
552
- # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
553
- #
554
- # Note: Although it is often much faster than the alternative, #destroy,
555
- # skipping callbacks might bypass business logic in your application
556
- # that ensures referential integrity or performs other essential jobs.
557
- #
558
- # ==== Examples
559
- #
560
- # # Delete a single row
561
- # Todo.delete(1)
562
- #
563
- # # Delete multiple rows
564
- # Todo.delete([2,3,4])
565
- def delete(id_or_array)
566
- delete_by(primary_key => id_or_array)
567
- end
568
-
569
- def _insert_record(values, returning) # :nodoc:
238
+ def _insert_record(connection, values, returning) # :nodoc:
570
239
  primary_key = self.primary_key
571
240
  primary_key_value = nil
572
241
 
@@ -605,7 +274,9 @@ module ActiveRecord
605
274
  um.set(values.transform_keys { |name| arel_table[name] })
606
275
  um.wheres = constraints
607
276
 
608
- connection.update(um, "#{self} Update")
277
+ with_connection do |c|
278
+ c.update(um, "#{self} Update")
279
+ end
609
280
  end
610
281
 
611
282
  def _delete_record(constraints) # :nodoc:
@@ -621,7 +292,9 @@ module ActiveRecord
621
292
  dm = Arel::DeleteManager.new(arel_table)
622
293
  dm.wheres = constraints
623
294
 
624
- connection.delete(dm, "#{self} Destroy")
295
+ with_connection do |c|
296
+ c.delete(dm, "#{self} Destroy")
297
+ end
625
298
  end
626
299
 
627
300
  private
@@ -1067,7 +740,7 @@ module ActiveRecord
1067
740
  # end
1068
741
  #
1069
742
  def reload(options = nil)
1070
- self.class.connection.clear_query_cache
743
+ self.class.connection_pool.clear_query_cache
1071
744
 
1072
745
  fresh_object = if apply_scoping?(options)
1073
746
  _find_record((options || {}).merge(all_queries: true))
@@ -1137,156 +810,159 @@ module ActiveRecord
1137
810
  end
1138
811
  end
1139
812
 
1140
- private
1141
- def init_internals
1142
- super
1143
- @_trigger_destroy_callback = @_trigger_update_callback = nil
1144
- @previously_new_record = false
1145
- end
813
+ private
814
+ def init_internals
815
+ super
816
+ @_trigger_destroy_callback = @_trigger_update_callback = nil
817
+ @previously_new_record = false
818
+ end
1146
819
 
1147
- def strict_loaded_associations
1148
- @association_cache.find_all do |_, assoc|
1149
- assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
1150
- end.map(&:first)
1151
- end
820
+ def strict_loaded_associations
821
+ @association_cache.find_all do |_, assoc|
822
+ assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
823
+ end.map(&:first)
824
+ end
1152
825
 
1153
- def _find_record(options)
1154
- all_queries = options ? options[:all_queries] : nil
1155
- base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
826
+ def _find_record(options)
827
+ all_queries = options ? options[:all_queries] : nil
828
+ base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
1156
829
 
1157
- if options && options[:lock]
1158
- base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
1159
- else
1160
- base.find_by!(_in_memory_query_constraints_hash)
830
+ if options && options[:lock]
831
+ base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
832
+ else
833
+ base.find_by!(_in_memory_query_constraints_hash)
834
+ end
1161
835
  end
1162
- end
1163
836
 
1164
- def _in_memory_query_constraints_hash
1165
- if self.class.query_constraints_list.nil?
1166
- { @primary_key => id }
1167
- else
1168
- self.class.query_constraints_list.index_with do |column_name|
1169
- attribute(column_name)
837
+ def _in_memory_query_constraints_hash
838
+ if self.class.query_constraints_list.nil?
839
+ { @primary_key => id }
840
+ else
841
+ self.class.query_constraints_list.index_with do |column_name|
842
+ attribute(column_name)
843
+ end
1170
844
  end
1171
845
  end
1172
- end
1173
846
 
1174
- def apply_scoping?(options)
1175
- !(options && options[:unscoped]) &&
1176
- (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
1177
- end
847
+ def apply_scoping?(options)
848
+ !(options && options[:unscoped]) &&
849
+ (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
850
+ end
1178
851
 
1179
- def _query_constraints_hash
1180
- if self.class.query_constraints_list.nil?
1181
- { @primary_key => id_in_database }
1182
- else
1183
- self.class.query_constraints_list.index_with do |column_name|
1184
- attribute_in_database(column_name)
852
+ def _query_constraints_hash
853
+ if self.class.query_constraints_list.nil?
854
+ { @primary_key => id_in_database }
855
+ else
856
+ self.class.query_constraints_list.index_with do |column_name|
857
+ attribute_in_database(column_name)
858
+ end
1185
859
  end
1186
860
  end
1187
- end
1188
-
1189
- # A hook to be overridden by association modules.
1190
- def destroy_associations
1191
- end
1192
-
1193
- def destroy_row
1194
- _delete_row
1195
- end
1196
861
 
1197
- def _delete_row
1198
- self.class._delete_record(_query_constraints_hash)
1199
- end
862
+ # A hook to be overridden by association modules.
863
+ def destroy_associations
864
+ end
1200
865
 
1201
- def _touch_row(attribute_names, time)
1202
- time ||= current_time_from_proper_timezone
866
+ def destroy_row
867
+ _delete_row
868
+ end
1203
869
 
1204
- attribute_names.each do |attr_name|
1205
- _write_attribute(attr_name, time)
870
+ def _delete_row
871
+ self.class._delete_record(_query_constraints_hash)
1206
872
  end
1207
873
 
1208
- _update_row(attribute_names, "touch")
1209
- end
874
+ def _touch_row(attribute_names, time)
875
+ time ||= current_time_from_proper_timezone
1210
876
 
1211
- def _update_row(attribute_names, attempted_action = "update")
1212
- self.class._update_record(
1213
- attributes_with_values(attribute_names),
1214
- _query_constraints_hash
1215
- )
1216
- end
877
+ attribute_names.each do |attr_name|
878
+ _write_attribute(attr_name, time)
879
+ end
1217
880
 
1218
- def create_or_update(**, &block)
1219
- _raise_readonly_record_error if readonly?
1220
- return false if destroyed?
1221
- result = new_record? ? _create_record(&block) : _update_record(&block)
1222
- result != false
1223
- end
881
+ _update_row(attribute_names, "touch")
882
+ end
1224
883
 
1225
- # Updates the associated record with values matching those of the instance attributes.
1226
- # Returns the number of affected rows.
1227
- def _update_record(attribute_names = self.attribute_names)
1228
- attribute_names = attributes_for_update(attribute_names)
884
+ def _update_row(attribute_names, attempted_action = "update")
885
+ self.class._update_record(
886
+ attributes_with_values(attribute_names),
887
+ _query_constraints_hash
888
+ )
889
+ end
1229
890
 
1230
- if attribute_names.empty?
1231
- affected_rows = 0
1232
- @_trigger_update_callback = true
1233
- else
1234
- affected_rows = _update_row(attribute_names)
1235
- @_trigger_update_callback = affected_rows == 1
891
+ def create_or_update(**, &block)
892
+ _raise_readonly_record_error if readonly?
893
+ return false if destroyed?
894
+ result = new_record? ? _create_record(&block) : _update_record(&block)
895
+ result != false
1236
896
  end
1237
897
 
1238
- @previously_new_record = false
898
+ # Updates the associated record with values matching those of the instance attributes.
899
+ # Returns the number of affected rows.
900
+ def _update_record(attribute_names = self.attribute_names)
901
+ attribute_names = attributes_for_update(attribute_names)
1239
902
 
1240
- yield(self) if block_given?
903
+ if attribute_names.empty?
904
+ affected_rows = 0
905
+ @_trigger_update_callback = true
906
+ else
907
+ affected_rows = _update_row(attribute_names)
908
+ @_trigger_update_callback = affected_rows == 1
909
+ end
1241
910
 
1242
- affected_rows
1243
- end
911
+ @previously_new_record = false
1244
912
 
1245
- # Creates a record with values matching those of the instance attributes
1246
- # and returns its id.
1247
- def _create_record(attribute_names = self.attribute_names)
1248
- attribute_names = attributes_for_create(attribute_names)
913
+ yield(self) if block_given?
1249
914
 
1250
- returning_columns = self.class._returning_columns_for_insert
915
+ affected_rows
916
+ end
1251
917
 
1252
- returning_values = self.class._insert_record(
1253
- attributes_with_values(attribute_names),
1254
- returning_columns
1255
- )
918
+ # Creates a record with values matching those of the instance attributes
919
+ # and returns its id.
920
+ def _create_record(attribute_names = self.attribute_names)
921
+ attribute_names = attributes_for_create(attribute_names)
1256
922
 
1257
- returning_columns.zip(returning_values).each do |column, value|
1258
- _write_attribute(column, value) if !_read_attribute(column)
1259
- end if returning_values
923
+ self.class.with_connection do |connection|
924
+ returning_columns = self.class._returning_columns_for_insert(connection)
1260
925
 
1261
- @new_record = false
1262
- @previously_new_record = true
926
+ returning_values = self.class._insert_record(
927
+ connection,
928
+ attributes_with_values(attribute_names),
929
+ returning_columns
930
+ )
1263
931
 
1264
- yield(self) if block_given?
932
+ returning_columns.zip(returning_values).each do |column, value|
933
+ _write_attribute(column, type_for_attribute(column).deserialize(value)) if !_read_attribute(column)
934
+ end if returning_values
935
+ end
1265
936
 
1266
- id
1267
- end
937
+ @new_record = false
938
+ @previously_new_record = true
1268
939
 
1269
- def verify_readonly_attribute(name)
1270
- raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
1271
- end
940
+ yield(self) if block_given?
1272
941
 
1273
- def _raise_record_not_destroyed
1274
- @_association_destroy_exception ||= nil
1275
- key = self.class.primary_key
1276
- raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
1277
- ensure
1278
- @_association_destroy_exception = nil
1279
- end
942
+ id
943
+ end
1280
944
 
1281
- def _raise_readonly_record_error
1282
- raise ReadOnlyRecord, "#{self.class} is marked as readonly"
1283
- end
945
+ def verify_readonly_attribute(name)
946
+ raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
947
+ end
1284
948
 
1285
- def _raise_record_not_touched_error
1286
- raise ActiveRecordError, <<~MSG.squish
1287
- Cannot touch on a new or destroyed record object. Consider using
1288
- persisted?, new_record?, or destroyed? before touching.
1289
- MSG
1290
- end
949
+ def _raise_record_not_destroyed
950
+ @_association_destroy_exception ||= nil
951
+ key = self.class.primary_key
952
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
953
+ ensure
954
+ @_association_destroy_exception = nil
955
+ end
956
+
957
+ def _raise_readonly_record_error
958
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly"
959
+ end
960
+
961
+ def _raise_record_not_touched_error
962
+ raise ActiveRecordError, <<~MSG.squish
963
+ Cannot touch on a new or destroyed record object. Consider using
964
+ persisted?, new_record?, or destroyed? before touching.
965
+ MSG
966
+ end
1291
967
  end
1292
968
  end