activerecord 7.1.5.2 → 8.1.2.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 (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +567 -2443
  3. data/README.rdoc +16 -16
  4. data/examples/performance.rb +2 -2
  5. data/lib/active_record/association_relation.rb +3 -2
  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 +31 -8
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  10. data/lib/active_record/associations/builder/association.rb +23 -11
  11. data/lib/active_record/associations/builder/belongs_to.rb +18 -4
  12. data/lib/active_record/associations/builder/collection_association.rb +7 -3
  13. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
  14. data/lib/active_record/associations/builder/has_many.rb +3 -4
  15. data/lib/active_record/associations/builder/has_one.rb +3 -4
  16. data/lib/active_record/associations/builder/singular_association.rb +33 -5
  17. data/lib/active_record/associations/collection_association.rb +17 -9
  18. data/lib/active_record/associations/collection_proxy.rb +36 -5
  19. data/lib/active_record/associations/deprecation.rb +88 -0
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  21. data/lib/active_record/associations/errors.rb +268 -0
  22. data/lib/active_record/associations/has_many_association.rb +1 -1
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -3
  24. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +4 -2
  26. data/lib/active_record/associations/nested_error.rb +47 -0
  27. data/lib/active_record/associations/preloader/association.rb +4 -3
  28. data/lib/active_record/associations/preloader/batch.rb +7 -1
  29. data/lib/active_record/associations/preloader/branch.rb +8 -1
  30. data/lib/active_record/associations/preloader/through_association.rb +1 -3
  31. data/lib/active_record/associations/singular_association.rb +14 -3
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +250 -315
  34. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  35. data/lib/active_record/attribute_assignment.rb +0 -2
  36. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  37. data/lib/active_record/attribute_methods/primary_key.rb +25 -61
  38. data/lib/active_record/attribute_methods/query.rb +34 -0
  39. data/lib/active_record/attribute_methods/read.rb +1 -13
  40. data/lib/active_record/attribute_methods/serialization.rb +20 -27
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +19 -20
  42. data/lib/active_record/attribute_methods.rb +71 -75
  43. data/lib/active_record/attributes.rb +96 -68
  44. data/lib/active_record/autosave_association.rb +93 -58
  45. data/lib/active_record/base.rb +5 -7
  46. data/lib/active_record/callbacks.rb +1 -1
  47. data/lib/active_record/coders/json.rb +14 -5
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +50 -126
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -4
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +52 -13
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +681 -135
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +165 -86
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +226 -78
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -114
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +11 -7
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -36
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +136 -34
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +163 -68
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -129
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -63
  62. data/lib/active_record/connection_adapters/column.rb +17 -4
  63. data/lib/active_record/connection_adapters/mysql/database_statements.rb +11 -3
  64. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
  65. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +41 -10
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +79 -46
  68. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +97 -101
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +14 -33
  70. data/lib/active_record/connection_adapters/pool_config.rb +14 -13
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +4 -0
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +98 -44
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +3 -3
  74. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  78. data/lib/active_record/connection_adapters/postgresql/quoting.rb +79 -68
  79. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
  80. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +9 -17
  81. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +44 -41
  82. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +69 -32
  83. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +155 -75
  84. data/lib/active_record/connection_adapters/postgresql_adapter.rb +104 -121
  85. data/lib/active_record/connection_adapters/schema_cache.rb +126 -133
  86. data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
  87. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +91 -95
  88. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -54
  89. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
  90. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
  91. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +43 -2
  92. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -15
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +231 -111
  94. data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
  95. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +40 -69
  96. data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
  97. data/lib/active_record/connection_adapters.rb +66 -0
  98. data/lib/active_record/connection_handling.rb +88 -46
  99. data/lib/active_record/core.rb +142 -58
  100. data/lib/active_record/counter_cache.rb +52 -18
  101. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
  102. data/lib/active_record/database_configurations/database_config.rb +28 -5
  103. data/lib/active_record/database_configurations/hash_config.rb +103 -41
  104. data/lib/active_record/database_configurations/url_config.rb +30 -1
  105. data/lib/active_record/database_configurations.rb +8 -4
  106. data/lib/active_record/delegated_type.rb +43 -19
  107. data/lib/active_record/dynamic_matchers.rb +56 -71
  108. data/lib/active_record/encryption/config.rb +3 -1
  109. data/lib/active_record/encryption/encryptable_record.rb +12 -12
  110. data/lib/active_record/encryption/encrypted_attribute_type.rb +35 -6
  111. data/lib/active_record/encryption/encryptor.rb +58 -22
  112. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  113. data/lib/active_record/encryption/key_provider.rb +1 -1
  114. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  115. data/lib/active_record/encryption/message_serializer.rb +4 -0
  116. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  117. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  118. data/lib/active_record/encryption/scheme.rb +9 -2
  119. data/lib/active_record/enum.rb +57 -36
  120. data/lib/active_record/errors.rb +76 -26
  121. data/lib/active_record/explain.rb +14 -25
  122. data/lib/active_record/explain_registry.rb +51 -2
  123. data/lib/active_record/filter_attribute_handler.rb +73 -0
  124. data/lib/active_record/fixture_set/table_row.rb +19 -2
  125. data/lib/active_record/fixtures.rb +39 -35
  126. data/lib/active_record/future_result.rb +21 -13
  127. data/lib/active_record/gem_version.rb +3 -3
  128. data/lib/active_record/inheritance.rb +5 -3
  129. data/lib/active_record/insert_all.rb +28 -20
  130. data/lib/active_record/integration.rb +4 -1
  131. data/lib/active_record/internal_metadata.rb +48 -34
  132. data/lib/active_record/locking/optimistic.rb +15 -7
  133. data/lib/active_record/locking/pessimistic.rb +5 -0
  134. data/lib/active_record/log_subscriber.rb +3 -34
  135. data/lib/active_record/message_pack.rb +1 -1
  136. data/lib/active_record/middleware/shard_selector.rb +34 -17
  137. data/lib/active_record/migration/command_recorder.rb +46 -14
  138. data/lib/active_record/migration/compatibility.rb +40 -25
  139. data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
  140. data/lib/active_record/migration/default_strategy.rb +4 -5
  141. data/lib/active_record/migration/pending_migration_connection.rb +2 -2
  142. data/lib/active_record/migration.rb +119 -103
  143. data/lib/active_record/model_schema.rb +66 -78
  144. data/lib/active_record/nested_attributes.rb +17 -9
  145. data/lib/active_record/persistence.rb +161 -454
  146. data/lib/active_record/query_cache.rb +33 -15
  147. data/lib/active_record/query_logs.rb +106 -39
  148. data/lib/active_record/query_logs_formatter.rb +17 -28
  149. data/lib/active_record/querying.rb +28 -16
  150. data/lib/active_record/railtie.rb +61 -74
  151. data/lib/active_record/railties/controller_runtime.rb +19 -5
  152. data/lib/active_record/railties/databases.rake +64 -78
  153. data/lib/active_record/railties/job_checkpoints.rb +15 -0
  154. data/lib/active_record/railties/job_runtime.rb +10 -11
  155. data/lib/active_record/reflection.rb +147 -53
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +153 -73
  158. data/lib/active_record/relation/calculations.rb +146 -96
  159. data/lib/active_record/relation/delegation.rb +30 -23
  160. data/lib/active_record/relation/finder_methods.rb +64 -34
  161. data/lib/active_record/relation/merger.rb +12 -14
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  163. data/lib/active_record/relation/predicate_builder/association_query_value.rb +19 -11
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +8 -8
  165. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  166. data/lib/active_record/relation/predicate_builder.rb +25 -10
  167. data/lib/active_record/relation/query_attribute.rb +4 -2
  168. data/lib/active_record/relation/query_methods.rb +351 -124
  169. data/lib/active_record/relation/spawn_methods.rb +9 -25
  170. data/lib/active_record/relation/where_clause.rb +17 -30
  171. data/lib/active_record/relation.rb +590 -124
  172. data/lib/active_record/result.rb +131 -59
  173. data/lib/active_record/runtime_registry.rb +44 -21
  174. data/lib/active_record/sanitization.rb +33 -25
  175. data/lib/active_record/schema.rb +8 -6
  176. data/lib/active_record/schema_dumper.rb +66 -31
  177. data/lib/active_record/schema_migration.rb +31 -14
  178. data/lib/active_record/scoping/named.rb +6 -2
  179. data/lib/active_record/scoping.rb +0 -1
  180. data/lib/active_record/secure_token.rb +3 -3
  181. data/lib/active_record/signed_id.rb +68 -20
  182. data/lib/active_record/statement_cache.rb +29 -25
  183. data/lib/active_record/store.rb +51 -22
  184. data/lib/active_record/structured_event_subscriber.rb +85 -0
  185. data/lib/active_record/table_metadata.rb +7 -33
  186. data/lib/active_record/tasks/abstract_tasks.rb +76 -0
  187. data/lib/active_record/tasks/database_tasks.rb +118 -90
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -42
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +17 -28
  191. data/lib/active_record/test_databases.rb +14 -4
  192. data/lib/active_record/test_fixtures.rb +123 -89
  193. data/lib/active_record/testing/query_assertions.rb +127 -0
  194. data/lib/active_record/timestamp.rb +6 -4
  195. data/lib/active_record/token_for.rb +22 -12
  196. data/lib/active_record/touch_later.rb +1 -1
  197. data/lib/active_record/transaction.rb +129 -0
  198. data/lib/active_record/transactions.rb +97 -18
  199. data/lib/active_record/translation.rb +0 -2
  200. data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
  201. data/lib/active_record/type/internal/timezone.rb +7 -0
  202. data/lib/active_record/type/json.rb +15 -2
  203. data/lib/active_record/type/serialized.rb +12 -7
  204. data/lib/active_record/type/type_map.rb +1 -1
  205. data/lib/active_record/type_caster/connection.rb +5 -4
  206. data/lib/active_record/validations/associated.rb +10 -4
  207. data/lib/active_record/validations/uniqueness.rb +23 -18
  208. data/lib/active_record/validations.rb +4 -1
  209. data/lib/active_record.rb +203 -59
  210. data/lib/arel/alias_predication.rb +3 -1
  211. data/lib/arel/collectors/bind.rb +4 -2
  212. data/lib/arel/collectors/composite.rb +7 -0
  213. data/lib/arel/collectors/sql_string.rb +2 -2
  214. data/lib/arel/collectors/substitute_binds.rb +3 -3
  215. data/lib/arel/crud.rb +8 -11
  216. data/lib/arel/delete_manager.rb +5 -0
  217. data/lib/arel/nodes/binary.rb +1 -7
  218. data/lib/arel/nodes/bound_sql_literal.rb +9 -5
  219. data/lib/arel/nodes/count.rb +2 -2
  220. data/lib/arel/nodes/delete_statement.rb +4 -2
  221. data/lib/arel/nodes/function.rb +4 -10
  222. data/lib/arel/nodes/named_function.rb +2 -2
  223. data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
  224. data/lib/arel/nodes/node.rb +6 -5
  225. data/lib/arel/nodes/sql_literal.rb +8 -1
  226. data/lib/arel/nodes/update_statement.rb +4 -2
  227. data/lib/arel/nodes.rb +2 -4
  228. data/lib/arel/predications.rb +1 -1
  229. data/lib/arel/select_manager.rb +14 -5
  230. data/lib/arel/table.rb +3 -7
  231. data/lib/arel/tree_manager.rb +3 -2
  232. data/lib/arel/update_manager.rb +7 -1
  233. data/lib/arel/visitors/dot.rb +3 -3
  234. data/lib/arel/visitors/mysql.rb +9 -4
  235. data/lib/arel/visitors/postgresql.rb +56 -12
  236. data/lib/arel/visitors/sqlite.rb +80 -8
  237. data/lib/arel/visitors/to_sql.rb +34 -37
  238. data/lib/arel.rb +10 -4
  239. data/lib/rails/generators/active_record/application_record/USAGE +1 -1
  240. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  241. metadata +23 -14
  242. data/lib/active_record/explain_subscriber.rb +0 -34
  243. data/lib/active_record/normalization.rb +0 -167
  244. 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
@@ -819,6 +492,7 @@ module ActiveRecord
819
492
  becoming.instance_variable_set(:@attributes, @attributes)
820
493
  becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
821
494
  becoming.instance_variable_set(:@new_record, new_record?)
495
+ becoming.instance_variable_set(:@previously_new_record, previously_new_record?)
822
496
  becoming.instance_variable_set(:@destroyed, destroyed?)
823
497
  becoming.errors.copy!(errors)
824
498
  end
@@ -908,8 +582,8 @@ module ActiveRecord
908
582
  end
909
583
 
910
584
  # Equivalent to <code>update_columns(name => value)</code>.
911
- def update_column(name, value)
912
- update_columns(name => value)
585
+ def update_column(name, value, touch: nil)
586
+ update_columns(name => value, touch: touch)
913
587
  end
914
588
 
915
589
  # Updates the attributes directly in the database issuing an UPDATE SQL
@@ -923,11 +597,25 @@ module ActiveRecord
923
597
  #
924
598
  # * \Validations are skipped.
925
599
  # * \Callbacks are skipped.
926
- # * +updated_at+/+updated_on+ are not updated.
600
+ # * +updated_at+/+updated_on+ are updated if the +touch+ option is set to +true+.
927
601
  # * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
928
602
  #
929
603
  # This method raises an ActiveRecord::ActiveRecordError when called on new
930
604
  # objects, or when at least one of the attributes is marked as readonly.
605
+ #
606
+ # ==== Parameters
607
+ #
608
+ # * <tt>:touch</tt> option - Touch the timestamp columns when updating.
609
+ # * If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
610
+ #
611
+ # ==== Examples
612
+ #
613
+ # # Update a single attribute.
614
+ # user.update_columns(last_request_at: Time.current)
615
+ #
616
+ # # Update with touch option.
617
+ # user.update_columns(last_request_at: Time.current, touch: true)
618
+
931
619
  def update_columns(attributes)
932
620
  raise ActiveRecordError, "cannot update a new record" if new_record?
933
621
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
@@ -939,6 +627,15 @@ module ActiveRecord
939
627
  verify_readonly_attribute(name) || name
940
628
  end
941
629
 
630
+ touch = attributes.delete("touch")
631
+ if touch
632
+ names = touch if touch != true
633
+ names = Array.wrap(names)
634
+ options = names.extract_options!
635
+ touch_updates = self.class.touch_attributes_with_time(*names, **options)
636
+ attributes.with_defaults!(touch_updates) unless touch_updates.empty?
637
+ end
638
+
942
639
  update_constraints = _query_constraints_hash
943
640
  attributes = attributes.each_with_object({}) do |(k, v), h|
944
641
  h[k] = @attributes.write_cast_value(k, v)
@@ -967,8 +664,15 @@ module ActiveRecord
967
664
  # This means that any other modified attributes will still be dirty.
968
665
  # Validations and callbacks are skipped. Supports the +touch+ option from
969
666
  # +update_counters+, see that for more.
667
+ #
668
+ # This method raises an ActiveRecord::ActiveRecordError when called on new
669
+ # objects, or when at least one of the attributes is marked as readonly.
670
+ #
970
671
  # Returns +self+.
971
672
  def increment!(attribute, by = 1, touch: nil)
673
+ raise ActiveRecordError, "cannot update a new record" if new_record?
674
+ raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
675
+
972
676
  increment(attribute, by)
973
677
  change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
974
678
  self.class.update_counters(id, attribute => change, touch: touch)
@@ -1067,7 +771,7 @@ module ActiveRecord
1067
771
  # end
1068
772
  #
1069
773
  def reload(options = nil)
1070
- self.class.connection.clear_query_cache
774
+ self.class.connection_pool.clear_query_cache
1071
775
 
1072
776
  fresh_object = if apply_scoping?(options)
1073
777
  _find_record((options || {}).merge(all_queries: true))
@@ -1137,156 +841,159 @@ module ActiveRecord
1137
841
  end
1138
842
  end
1139
843
 
1140
- private
1141
- def init_internals
1142
- super
1143
- @_trigger_destroy_callback = @_trigger_update_callback = nil
1144
- @previously_new_record = false
1145
- end
844
+ private
845
+ def init_internals
846
+ super
847
+ @_trigger_destroy_callback = @_trigger_update_callback = nil
848
+ @previously_new_record = false
849
+ end
1146
850
 
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
851
+ def strict_loaded_associations
852
+ @association_cache.find_all do |_, assoc|
853
+ assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
854
+ end.map(&:first)
855
+ end
1152
856
 
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)
857
+ def _find_record(options)
858
+ all_queries = options ? options[:all_queries] : nil
859
+ base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
1156
860
 
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)
861
+ if options && options[:lock]
862
+ base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
863
+ else
864
+ base.find_by!(_in_memory_query_constraints_hash)
865
+ end
1161
866
  end
1162
- end
1163
867
 
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)
868
+ def _in_memory_query_constraints_hash
869
+ if self.class.query_constraints_list.nil?
870
+ { @primary_key => id }
871
+ else
872
+ self.class.query_constraints_list.index_with do |column_name|
873
+ attribute(column_name)
874
+ end
1170
875
  end
1171
876
  end
1172
- end
1173
877
 
1174
- def apply_scoping?(options)
1175
- !(options && options[:unscoped]) &&
1176
- (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
1177
- end
878
+ def apply_scoping?(options)
879
+ !(options && options[:unscoped]) &&
880
+ (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
881
+ end
1178
882
 
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)
883
+ def _query_constraints_hash
884
+ if self.class.query_constraints_list.nil?
885
+ { @primary_key => id_in_database }
886
+ else
887
+ self.class.query_constraints_list.index_with do |column_name|
888
+ attribute_in_database(column_name)
889
+ end
1185
890
  end
1186
891
  end
1187
- end
1188
892
 
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
-
1197
- def _delete_row
1198
- self.class._delete_record(_query_constraints_hash)
1199
- end
893
+ # A hook to be overridden by association modules.
894
+ def destroy_associations
895
+ end
1200
896
 
1201
- def _touch_row(attribute_names, time)
1202
- time ||= current_time_from_proper_timezone
897
+ def destroy_row
898
+ _delete_row
899
+ end
1203
900
 
1204
- attribute_names.each do |attr_name|
1205
- _write_attribute(attr_name, time)
901
+ def _delete_row
902
+ self.class._delete_record(_query_constraints_hash)
1206
903
  end
1207
904
 
1208
- _update_row(attribute_names, "touch")
1209
- end
905
+ def _touch_row(attribute_names, time)
906
+ time ||= current_time_from_proper_timezone
1210
907
 
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
908
+ attribute_names.each do |attr_name|
909
+ _write_attribute(attr_name, time)
910
+ end
1217
911
 
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
912
+ _update_row(attribute_names, "touch")
913
+ end
1224
914
 
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)
915
+ def _update_row(attribute_names, attempted_action = "update")
916
+ self.class._update_record(
917
+ attributes_with_values(attribute_names),
918
+ _query_constraints_hash
919
+ )
920
+ end
1229
921
 
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
922
+ def create_or_update(**, &block)
923
+ _raise_readonly_record_error if readonly?
924
+ return false if destroyed?
925
+ result = new_record? ? _create_record(&block) : _update_record(&block)
926
+ result != false
1236
927
  end
1237
928
 
1238
- @previously_new_record = false
929
+ # Updates the associated record with values matching those of the instance attributes.
930
+ # Returns the number of affected rows.
931
+ def _update_record(attribute_names = self.attribute_names)
932
+ attribute_names = attributes_for_update(attribute_names)
1239
933
 
1240
- yield(self) if block_given?
934
+ if attribute_names.empty?
935
+ affected_rows = 0
936
+ @_trigger_update_callback = true
937
+ else
938
+ affected_rows = _update_row(attribute_names)
939
+ @_trigger_update_callback = affected_rows == 1
940
+ end
1241
941
 
1242
- affected_rows
1243
- end
942
+ @previously_new_record = false
1244
943
 
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)
944
+ yield(self) if block_given?
1249
945
 
1250
- returning_columns = self.class._returning_columns_for_insert
946
+ affected_rows
947
+ end
1251
948
 
1252
- returning_values = self.class._insert_record(
1253
- attributes_with_values(attribute_names),
1254
- returning_columns
1255
- )
949
+ # Creates a record with values matching those of the instance attributes
950
+ # and returns its id.
951
+ def _create_record(attribute_names = self.attribute_names)
952
+ attribute_names = attributes_for_create(attribute_names)
1256
953
 
1257
- returning_columns.zip(returning_values).each do |column, value|
1258
- _write_attribute(column, value) if !_read_attribute(column)
1259
- end if returning_values
954
+ self.class.with_connection do |connection|
955
+ returning_columns = self.class._returning_columns_for_insert(connection)
1260
956
 
1261
- @new_record = false
1262
- @previously_new_record = true
957
+ returning_values = self.class._insert_record(
958
+ connection,
959
+ attributes_with_values(attribute_names),
960
+ returning_columns
961
+ )
1263
962
 
1264
- yield(self) if block_given?
963
+ returning_columns.zip(returning_values).each do |column, value|
964
+ _write_attribute(column, type_for_attribute(column).deserialize(value)) if !_read_attribute(column)
965
+ end if returning_values
966
+ end
1265
967
 
1266
- id
1267
- end
968
+ @new_record = false
969
+ @previously_new_record = true
1268
970
 
1269
- def verify_readonly_attribute(name)
1270
- raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
1271
- end
971
+ yield(self) if block_given?
1272
972
 
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
973
+ id
974
+ end
1280
975
 
1281
- def _raise_readonly_record_error
1282
- raise ReadOnlyRecord, "#{self.class} is marked as readonly"
1283
- end
976
+ def verify_readonly_attribute(name)
977
+ raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attribute?(name)
978
+ end
1284
979
 
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
980
+ def _raise_record_not_destroyed
981
+ @_association_destroy_exception ||= nil
982
+ key = self.class.primary_key
983
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
984
+ ensure
985
+ @_association_destroy_exception = nil
986
+ end
987
+
988
+ def _raise_readonly_record_error
989
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly"
990
+ end
991
+
992
+ def _raise_record_not_touched_error
993
+ raise ActiveRecordError, <<~MSG.squish
994
+ Cannot touch on a new or destroyed record object. Consider using
995
+ persisted?, new_record?, or destroyed? before touching.
996
+ MSG
997
+ end
1291
998
  end
1292
999
  end