activerecord 6.1.7.8 → 7.0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1582 -1018
  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 +53 -9
@@ -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?