activerecord 6.1.6 → 7.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (309) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1627 -983
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +50 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +35 -31
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency.rb +26 -16
  27. data/lib/active_record/associations/preloader/association.rb +207 -52
  28. data/lib/active_record/associations/preloader/batch.rb +48 -0
  29. data/lib/active_record/associations/preloader/branch.rb +147 -0
  30. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  31. data/lib/active_record/associations/preloader.rb +50 -121
  32. data/lib/active_record/associations/singular_association.rb +9 -3
  33. data/lib/active_record/associations/through_association.rb +25 -14
  34. data/lib/active_record/associations.rb +439 -305
  35. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  36. data/lib/active_record/attribute_assignment.rb +1 -3
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  39. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  40. data/lib/active_record/attribute_methods/query.rb +31 -19
  41. data/lib/active_record/attribute_methods/read.rb +25 -10
  42. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  44. data/lib/active_record/attribute_methods/write.rb +10 -13
  45. data/lib/active_record/attribute_methods.rb +121 -40
  46. data/lib/active_record/attributes.rb +27 -38
  47. data/lib/active_record/autosave_association.rb +61 -30
  48. data/lib/active_record/base.rb +25 -2
  49. data/lib/active_record/callbacks.rb +18 -34
  50. data/lib/active_record/coders/column_serializer.rb +61 -0
  51. data/lib/active_record/coders/json.rb +1 -1
  52. data/lib/active_record/coders/yaml_column.rb +70 -34
  53. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  54. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -138
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -149
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
  69. data/lib/active_record/connection_adapters/column.rb +13 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  83. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  87. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  89. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  93. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  94. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  95. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  96. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  97. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  98. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +394 -74
  99. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  100. data/lib/active_record/connection_adapters/postgresql_adapter.rb +509 -247
  101. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  102. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  103. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  104. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  105. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  106. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  107. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
  108. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  109. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  110. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  111. data/lib/active_record/connection_adapters.rb +9 -6
  112. data/lib/active_record/connection_handling.rb +107 -136
  113. data/lib/active_record/core.rb +202 -223
  114. data/lib/active_record/counter_cache.rb +46 -25
  115. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  116. data/lib/active_record/database_configurations/database_config.rb +21 -12
  117. data/lib/active_record/database_configurations/hash_config.rb +84 -16
  118. data/lib/active_record/database_configurations/url_config.rb +18 -12
  119. data/lib/active_record/database_configurations.rb +95 -59
  120. data/lib/active_record/delegated_type.rb +61 -15
  121. data/lib/active_record/deprecator.rb +7 -0
  122. data/lib/active_record/destroy_association_async_job.rb +3 -1
  123. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  124. data/lib/active_record/dynamic_matchers.rb +1 -1
  125. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  126. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  127. data/lib/active_record/encryption/cipher.rb +53 -0
  128. data/lib/active_record/encryption/config.rb +68 -0
  129. data/lib/active_record/encryption/configurable.rb +60 -0
  130. data/lib/active_record/encryption/context.rb +42 -0
  131. data/lib/active_record/encryption/contexts.rb +76 -0
  132. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  133. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  134. data/lib/active_record/encryption/encryptable_record.rb +224 -0
  135. data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
  136. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  137. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  138. data/lib/active_record/encryption/encryptor.rb +155 -0
  139. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  140. data/lib/active_record/encryption/errors.rb +15 -0
  141. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  142. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  143. data/lib/active_record/encryption/key.rb +28 -0
  144. data/lib/active_record/encryption/key_generator.rb +53 -0
  145. data/lib/active_record/encryption/key_provider.rb +46 -0
  146. data/lib/active_record/encryption/message.rb +33 -0
  147. data/lib/active_record/encryption/message_serializer.rb +92 -0
  148. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  149. data/lib/active_record/encryption/properties.rb +76 -0
  150. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  151. data/lib/active_record/encryption/scheme.rb +96 -0
  152. data/lib/active_record/encryption.rb +56 -0
  153. data/lib/active_record/enum.rb +154 -63
  154. data/lib/active_record/errors.rb +171 -15
  155. data/lib/active_record/explain.rb +23 -3
  156. data/lib/active_record/explain_registry.rb +11 -6
  157. data/lib/active_record/explain_subscriber.rb +1 -1
  158. data/lib/active_record/fixture_set/file.rb +15 -1
  159. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  160. data/lib/active_record/fixture_set/render_context.rb +2 -0
  161. data/lib/active_record/fixture_set/table_row.rb +70 -14
  162. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  163. data/lib/active_record/fixtures.rb +131 -86
  164. data/lib/active_record/future_result.rb +164 -0
  165. data/lib/active_record/gem_version.rb +3 -3
  166. data/lib/active_record/inheritance.rb +81 -29
  167. data/lib/active_record/insert_all.rb +135 -22
  168. data/lib/active_record/integration.rb +11 -10
  169. data/lib/active_record/internal_metadata.rb +119 -33
  170. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  171. data/lib/active_record/locking/optimistic.rb +36 -21
  172. data/lib/active_record/locking/pessimistic.rb +15 -6
  173. data/lib/active_record/log_subscriber.rb +52 -19
  174. data/lib/active_record/marshalling.rb +56 -0
  175. data/lib/active_record/message_pack.rb +124 -0
  176. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  177. data/lib/active_record/middleware/database_selector.rb +23 -13
  178. data/lib/active_record/middleware/shard_selector.rb +62 -0
  179. data/lib/active_record/migration/command_recorder.rb +112 -14
  180. data/lib/active_record/migration/compatibility.rb +221 -48
  181. data/lib/active_record/migration/default_strategy.rb +23 -0
  182. data/lib/active_record/migration/execution_strategy.rb +19 -0
  183. data/lib/active_record/migration/join_table.rb +1 -1
  184. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  185. data/lib/active_record/migration.rb +358 -171
  186. data/lib/active_record/model_schema.rb +120 -101
  187. data/lib/active_record/nested_attributes.rb +37 -18
  188. data/lib/active_record/no_touching.rb +3 -3
  189. data/lib/active_record/normalization.rb +167 -0
  190. data/lib/active_record/persistence.rb +405 -85
  191. data/lib/active_record/promise.rb +84 -0
  192. data/lib/active_record/query_cache.rb +3 -21
  193. data/lib/active_record/query_logs.rb +174 -0
  194. data/lib/active_record/query_logs_formatter.rb +41 -0
  195. data/lib/active_record/querying.rb +29 -6
  196. data/lib/active_record/railtie.rb +219 -43
  197. data/lib/active_record/railties/controller_runtime.rb +13 -9
  198. data/lib/active_record/railties/databases.rake +188 -252
  199. data/lib/active_record/railties/job_runtime.rb +23 -0
  200. data/lib/active_record/readonly_attributes.rb +41 -3
  201. data/lib/active_record/reflection.rb +241 -80
  202. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  203. data/lib/active_record/relation/batches.rb +192 -63
  204. data/lib/active_record/relation/calculations.rb +219 -90
  205. data/lib/active_record/relation/delegation.rb +27 -13
  206. data/lib/active_record/relation/finder_methods.rb +108 -51
  207. data/lib/active_record/relation/merger.rb +22 -13
  208. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  209. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  210. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  211. data/lib/active_record/relation/predicate_builder.rb +27 -20
  212. data/lib/active_record/relation/query_attribute.rb +30 -12
  213. data/lib/active_record/relation/query_methods.rb +654 -127
  214. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  215. data/lib/active_record/relation/spawn_methods.rb +20 -3
  216. data/lib/active_record/relation/where_clause.rb +10 -19
  217. data/lib/active_record/relation.rb +262 -120
  218. data/lib/active_record/result.rb +37 -11
  219. data/lib/active_record/runtime_registry.rb +18 -13
  220. data/lib/active_record/sanitization.rb +65 -20
  221. data/lib/active_record/schema.rb +36 -22
  222. data/lib/active_record/schema_dumper.rb +73 -24
  223. data/lib/active_record/schema_migration.rb +68 -33
  224. data/lib/active_record/scoping/default.rb +72 -15
  225. data/lib/active_record/scoping/named.rb +5 -13
  226. data/lib/active_record/scoping.rb +65 -34
  227. data/lib/active_record/secure_password.rb +60 -0
  228. data/lib/active_record/secure_token.rb +21 -3
  229. data/lib/active_record/serialization.rb +6 -1
  230. data/lib/active_record/signed_id.rb +10 -8
  231. data/lib/active_record/store.rb +16 -11
  232. data/lib/active_record/suppressor.rb +13 -15
  233. data/lib/active_record/table_metadata.rb +16 -3
  234. data/lib/active_record/tasks/database_tasks.rb +225 -136
  235. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  236. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  237. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  238. data/lib/active_record/test_databases.rb +1 -1
  239. data/lib/active_record/test_fixtures.rb +123 -99
  240. data/lib/active_record/timestamp.rb +29 -18
  241. data/lib/active_record/token_for.rb +113 -0
  242. data/lib/active_record/touch_later.rb +11 -6
  243. data/lib/active_record/transactions.rb +48 -27
  244. data/lib/active_record/translation.rb +3 -3
  245. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  246. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  247. data/lib/active_record/type/internal/timezone.rb +7 -2
  248. data/lib/active_record/type/serialized.rb +9 -5
  249. data/lib/active_record/type/time.rb +4 -0
  250. data/lib/active_record/type/type_map.rb +17 -20
  251. data/lib/active_record/type.rb +1 -2
  252. data/lib/active_record/validations/absence.rb +1 -1
  253. data/lib/active_record/validations/associated.rb +4 -4
  254. data/lib/active_record/validations/numericality.rb +5 -4
  255. data/lib/active_record/validations/presence.rb +5 -28
  256. data/lib/active_record/validations/uniqueness.rb +51 -6
  257. data/lib/active_record/validations.rb +8 -4
  258. data/lib/active_record/version.rb +1 -1
  259. data/lib/active_record.rb +335 -32
  260. data/lib/arel/attributes/attribute.rb +0 -8
  261. data/lib/arel/crud.rb +28 -22
  262. data/lib/arel/delete_manager.rb +18 -4
  263. data/lib/arel/errors.rb +10 -0
  264. data/lib/arel/factory_methods.rb +4 -0
  265. data/lib/arel/filter_predications.rb +9 -0
  266. data/lib/arel/insert_manager.rb +2 -3
  267. data/lib/arel/nodes/and.rb +4 -0
  268. data/lib/arel/nodes/binary.rb +6 -1
  269. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  270. data/lib/arel/nodes/casted.rb +1 -1
  271. data/lib/arel/nodes/cte.rb +36 -0
  272. data/lib/arel/nodes/delete_statement.rb +12 -13
  273. data/lib/arel/nodes/filter.rb +10 -0
  274. data/lib/arel/nodes/fragments.rb +35 -0
  275. data/lib/arel/nodes/function.rb +1 -0
  276. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  277. data/lib/arel/nodes/insert_statement.rb +2 -2
  278. data/lib/arel/nodes/leading_join.rb +8 -0
  279. data/lib/arel/nodes/node.rb +111 -2
  280. data/lib/arel/nodes/select_core.rb +2 -2
  281. data/lib/arel/nodes/select_statement.rb +2 -2
  282. data/lib/arel/nodes/sql_literal.rb +6 -0
  283. data/lib/arel/nodes/table_alias.rb +4 -0
  284. data/lib/arel/nodes/update_statement.rb +8 -3
  285. data/lib/arel/nodes.rb +5 -0
  286. data/lib/arel/predications.rb +13 -3
  287. data/lib/arel/select_manager.rb +10 -4
  288. data/lib/arel/table.rb +9 -6
  289. data/lib/arel/tree_manager.rb +0 -12
  290. data/lib/arel/update_manager.rb +18 -4
  291. data/lib/arel/visitors/dot.rb +80 -90
  292. data/lib/arel/visitors/mysql.rb +16 -3
  293. data/lib/arel/visitors/postgresql.rb +0 -10
  294. data/lib/arel/visitors/to_sql.rb +139 -19
  295. data/lib/arel/visitors/visitor.rb +2 -2
  296. data/lib/arel.rb +18 -3
  297. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  298. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  299. data/lib/rails/generators/active_record/migration.rb +3 -1
  300. data/lib/rails/generators/active_record/model/USAGE +113 -0
  301. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  302. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  303. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  304. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  305. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  306. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  307. metadata +93 -13
  308. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  309. data/lib/active_record/null_relation.rb +0 -67
@@ -57,14 +57,44 @@ module ActiveRecord
57
57
  end
58
58
  end
59
59
 
60
+ # Builds an object (or multiple objects) and returns either the built object or a list of built
61
+ # objects.
62
+ #
63
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
64
+ # attributes on the objects that are to be built.
65
+ #
66
+ # ==== Examples
67
+ # # Build a single new object
68
+ # User.build(first_name: 'Jamie')
69
+ #
70
+ # # Build an Array of new objects
71
+ # User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
72
+ #
73
+ # # Build a single object and pass it into a block to set other attributes.
74
+ # User.build(first_name: 'Jamie') do |u|
75
+ # u.is_admin = false
76
+ # end
77
+ #
78
+ # # Building an Array of new objects using a block, where the block is executed for each object:
79
+ # User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
80
+ # u.is_admin = false
81
+ # end
82
+ def build(attributes = nil, &block)
83
+ if attributes.is_a?(Array)
84
+ attributes.collect { |attr| build(attr, &block) }
85
+ else
86
+ new(attributes, &block)
87
+ end
88
+ end
89
+
60
90
  # Inserts a single record into the database in a single SQL INSERT
61
91
  # statement. It does not instantiate any models nor does it trigger
62
92
  # Active Record callbacks or validations. Though passed values
63
93
  # go through Active Record's type casting and serialization.
64
94
  #
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)
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)
68
98
  end
69
99
 
70
100
  # Inserts multiple records into the database in a single SQL INSERT
@@ -79,7 +109,7 @@ module ActiveRecord
79
109
  # duplicate rows are skipped.
80
110
  # Override with <tt>:unique_by</tt> (see below).
81
111
  #
82
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
112
+ # Returns an ActiveRecord::Result with its contents based on
83
113
  # <tt>:returning</tt> (see below).
84
114
  #
85
115
  # ==== Options
@@ -91,6 +121,9 @@ module ActiveRecord
91
121
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
92
122
  # clause entirely.
93
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
+ #
94
127
  # [:unique_by]
95
128
  # (PostgreSQL and SQLite only) By default rows are considered to be unique
96
129
  # by every unique index on the table. Any duplicate rows are skipped.
@@ -99,7 +132,7 @@ module ActiveRecord
99
132
  #
100
133
  # Consider a Book model where no duplicate ISBNs make sense, but if any
101
134
  # row has an existing id, or is not unique by another unique index,
102
- # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
135
+ # ActiveRecord::RecordNotUnique is raised.
103
136
  #
104
137
  # Unique indexes can be identified by columns or name:
105
138
  #
@@ -107,6 +140,17 @@ module ActiveRecord
107
140
  # unique_by: %i[ author_id name ]
108
141
  # unique_by: :index_books_on_isbn
109
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
+ #
110
154
  # Because it relies on the index information from the database
111
155
  # <tt>:unique_by</tt> is recommended to be paired with
112
156
  # Active Record's schema_cache.
@@ -120,8 +164,16 @@ module ActiveRecord
120
164
  # { id: 1, title: "Rework", author: "David" },
121
165
  # { id: 1, title: "Eloquent Ruby", author: "Russ" }
122
166
  # ])
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
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
125
177
  end
126
178
 
127
179
  # Inserts a single record into the database in a single SQL INSERT
@@ -129,9 +181,9 @@ module ActiveRecord
129
181
  # Active Record callbacks or validations. Though passed values
130
182
  # go through Active Record's type casting and serialization.
131
183
  #
132
- # See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
133
- def insert!(attributes, returning: nil)
134
- insert_all!([ attributes ], returning: returning)
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)
135
187
  end
136
188
 
137
189
  # Inserts multiple records into the database in a single SQL INSERT
@@ -142,13 +194,12 @@ module ActiveRecord
142
194
  # The +attributes+ parameter is an Array of Hashes. Every Hash determines
143
195
  # the attributes for a single row and must have the same keys.
144
196
  #
145
- # Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
197
+ # Raises ActiveRecord::RecordNotUnique if any rows violate a
146
198
  # unique index on the table. In that case, no rows are inserted.
147
199
  #
148
- # To skip duplicate rows, see <tt>ActiveRecord::Persistence#insert_all</tt>.
149
- # To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
200
+ # To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
150
201
  #
151
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
202
+ # Returns an ActiveRecord::Result with its contents based on
152
203
  # <tt>:returning</tt> (see below).
153
204
  #
154
205
  # ==== Options
@@ -160,6 +211,20 @@ module ActiveRecord
160
211
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
161
212
  # clause entirely.
162
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
+ #
163
228
  # ==== Examples
164
229
  #
165
230
  # # Insert multiple records
@@ -174,8 +239,8 @@ module ActiveRecord
174
239
  # { id: 1, title: "Rework", author: "David" },
175
240
  # { id: 1, title: "Eloquent Ruby", author: "Russ" }
176
241
  # ])
177
- def insert_all!(attributes, returning: nil)
178
- InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning).execute
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
179
244
  end
180
245
 
181
246
  # Updates or inserts (upserts) a single record into the database in a
@@ -183,9 +248,9 @@ module ActiveRecord
183
248
  # it trigger Active Record callbacks or validations. Though passed values
184
249
  # go through Active Record's type casting and serialization.
185
250
  #
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)
251
+ # See #upsert_all for documentation.
252
+ def upsert(attributes, **kwargs)
253
+ upsert_all([ attributes ], **kwargs)
189
254
  end
190
255
 
191
256
  # Updates or inserts (upserts) multiple records into the database in a
@@ -196,9 +261,13 @@ module ActiveRecord
196
261
  # The +attributes+ parameter is an Array of Hashes. Every Hash determines
197
262
  # the attributes for a single row and must have the same keys.
198
263
  #
199
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
264
+ # Returns an ActiveRecord::Result with its contents based on
200
265
  # <tt>:returning</tt> (see below).
201
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
+ #
202
271
  # ==== Options
203
272
  #
204
273
  # [:returning]
@@ -208,6 +277,9 @@ module ActiveRecord
208
277
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
209
278
  # clause entirely.
210
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
+ #
211
283
  # [:unique_by]
212
284
  # (PostgreSQL and SQLite only) By default rows are considered to be unique
213
285
  # by every unique index on the table. Any duplicate rows are skipped.
@@ -216,7 +288,7 @@ module ActiveRecord
216
288
  #
217
289
  # Consider a Book model where no duplicate ISBNs make sense, but if any
218
290
  # row has an existing id, or is not unique by another unique index,
219
- # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
291
+ # ActiveRecord::RecordNotUnique is raised.
220
292
  #
221
293
  # Unique indexes can be identified by columns or name:
222
294
  #
@@ -228,6 +300,54 @@ module ActiveRecord
228
300
  # <tt>:unique_by</tt> is recommended to be paired with
229
301
  # Active Record's schema_cache.
230
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
+ #
231
351
  # ==== Examples
232
352
  #
233
353
  # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
@@ -239,8 +359,8 @@ module ActiveRecord
239
359
  # ], unique_by: :isbn)
240
360
  #
241
361
  # 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
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
244
364
  end
245
365
 
246
366
  # Given an attributes hash, +instantiate+ returns a new instance of
@@ -264,6 +384,7 @@ module ActiveRecord
264
384
  # ==== Parameters
265
385
  #
266
386
  # * +id+ - This should be the id or an array of ids to be updated.
387
+ # Optional argument, defaults to all records in the relation.
267
388
  # * +attributes+ - This should be a hash of attributes or an array of hashes.
268
389
  #
269
390
  # ==== Examples
@@ -286,6 +407,11 @@ module ActiveRecord
286
407
  # for updating all records in a single query.
287
408
  def update(id = :all, attributes)
288
409
  if id.is_a?(Array)
410
+ if id.any?(ActiveRecord::Base)
411
+ raise ArgumentError,
412
+ "You are passing an array of ActiveRecord::Base instances to `update`. " \
413
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
414
+ end
289
415
  id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
290
416
  object.update(attributes[idx])
291
417
  }
@@ -303,6 +429,88 @@ module ActiveRecord
303
429
  end
304
430
  end
305
431
 
432
+ # Updates the object (or multiple objects) just like #update but calls #update! instead
433
+ # of +update+, so an exception is raised if the record is invalid and saving will fail.
434
+ def update!(id = :all, attributes)
435
+ if id.is_a?(Array)
436
+ if id.any?(ActiveRecord::Base)
437
+ raise ArgumentError,
438
+ "You are passing an array of ActiveRecord::Base instances to `update!`. " \
439
+ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`."
440
+ end
441
+ id.map { |one_id| find(one_id) }.each_with_index { |object, idx|
442
+ object.update!(attributes[idx])
443
+ }
444
+ elsif id == :all
445
+ all.each { |record| record.update!(attributes) }
446
+ else
447
+ if ActiveRecord::Base === id
448
+ raise ArgumentError,
449
+ "You are passing an instance of ActiveRecord::Base to `update!`. " \
450
+ "Please pass the id of the object by calling `.id`."
451
+ end
452
+ object = find(id)
453
+ object.update!(attributes)
454
+ object
455
+ end
456
+ end
457
+
458
+ # Accepts a list of attribute names to be used in the WHERE clause
459
+ # of SELECT / UPDATE / DELETE queries and in the ORDER BY clause for `#first` and `#last` finder methods.
460
+ #
461
+ # class Developer < ActiveRecord::Base
462
+ # query_constraints :company_id, :id
463
+ # end
464
+ #
465
+ # developer = Developer.first
466
+ # # SELECT "developers".* FROM "developers" ORDER BY "developers"."company_id" ASC, "developers"."id" ASC LIMIT 1
467
+ # developer.inspect # => #<Developer id: 1, company_id: 1, ...>
468
+ #
469
+ # developer.update!(name: "Nikita")
470
+ # # UPDATE "developers" SET "name" = 'Nikita' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
471
+ #
472
+ # It is possible to update attribute used in the query_by clause:
473
+ # developer.update!(company_id: 2)
474
+ # # UPDATE "developers" SET "company_id" = 2 WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
475
+ #
476
+ # developer.name = "Bob"
477
+ # developer.save!
478
+ # # UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
479
+ #
480
+ # developer.destroy!
481
+ # # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
482
+ #
483
+ # developer.delete
484
+ # # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
485
+ #
486
+ # developer.reload
487
+ # # SELECT "developers".* FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1 LIMIT 1
488
+ def query_constraints(*columns_list)
489
+ raise ArgumentError, "You must specify at least one column to be used in querying" if columns_list.empty?
490
+
491
+ @query_constraints_list = columns_list.map(&:to_s)
492
+ @has_query_constraints = @query_constraints_list
493
+ end
494
+
495
+ def has_query_constraints? # :nodoc:
496
+ @has_query_constraints
497
+ end
498
+
499
+ def query_constraints_list # :nodoc:
500
+ @query_constraints_list ||= if base_class? || primary_key != base_class.primary_key
501
+ primary_key if primary_key.is_a?(Array)
502
+ else
503
+ base_class.query_constraints_list
504
+ end
505
+ end
506
+
507
+ # Returns an array of column names to be used in queries. The source of column
508
+ # names is derived from +query_constraints_list+ or +primary_key+. This method
509
+ # is for internal use when the primary key is to be treated as an array.
510
+ def composite_query_constraints_list # :nodoc:
511
+ @composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
512
+ end
513
+
306
514
  # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
307
515
  # therefore all callbacks and filters are fired off before the object is deleted. This method is
308
516
  # less efficient than #delete but allows cleanup methods and other actions to be run.
@@ -323,7 +531,13 @@ module ActiveRecord
323
531
  # todos = [1,2,3]
324
532
  # Todo.destroy(todos)
325
533
  def destroy(id)
326
- if id.is_a?(Array)
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
327
541
  find(id).each(&:destroy)
328
542
  else
329
543
  find(id).destroy
@@ -352,50 +566,73 @@ module ActiveRecord
352
566
  delete_by(primary_key => id_or_array)
353
567
  end
354
568
 
355
- def _insert_record(values) # :nodoc:
569
+ def _insert_record(values, returning) # :nodoc:
356
570
  primary_key = self.primary_key
357
571
  primary_key_value = nil
358
572
 
359
- if primary_key && Hash === values
360
- primary_key_value = values[primary_key]
361
-
362
- if !primary_key_value && prefetch_primary_key?
573
+ if prefetch_primary_key? && primary_key
574
+ values[primary_key] ||= begin
363
575
  primary_key_value = next_sequence_value
364
- values[primary_key] = primary_key_value
576
+ _default_attributes[primary_key].with_cast_value(primary_key_value)
365
577
  end
366
578
  end
367
579
 
580
+ im = Arel::InsertManager.new(arel_table)
581
+
368
582
  if values.empty?
369
- im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
370
- im.into arel_table
583
+ im.insert(connection.empty_insert_statement_value(primary_key))
371
584
  else
372
- im = arel_table.compile_insert(_substitute_values(values))
585
+ im.insert(values.transform_keys { |name| arel_table[name] })
373
586
  end
374
587
 
375
- connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
588
+ connection.insert(
589
+ im, "#{self} Create", primary_key || false, primary_key_value,
590
+ returning: returning
591
+ )
376
592
  end
377
593
 
378
594
  def _update_record(values, constraints) # :nodoc:
379
- constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
595
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
596
+
597
+ default_constraint = build_default_constraint
598
+ constraints << default_constraint if default_constraint
599
+
600
+ if current_scope = self.global_current_scope
601
+ constraints << current_scope.where_clause.ast
602
+ end
380
603
 
381
- um = arel_table.where(
382
- constraints.reduce(&:and)
383
- ).compile_update(_substitute_values(values), primary_key)
604
+ um = Arel::UpdateManager.new(arel_table)
605
+ um.set(values.transform_keys { |name| arel_table[name] })
606
+ um.wheres = constraints
384
607
 
385
608
  connection.update(um, "#{self} Update")
386
609
  end
387
610
 
388
611
  def _delete_record(constraints) # :nodoc:
389
- constraints = _substitute_values(constraints).map { |attr, bind| attr.eq(bind) }
612
+ constraints = constraints.map { |name, value| predicate_builder[name, value] }
390
613
 
391
- dm = Arel::DeleteManager.new
392
- dm.from(arel_table)
614
+ default_constraint = build_default_constraint
615
+ constraints << default_constraint if default_constraint
616
+
617
+ if current_scope = self.global_current_scope
618
+ constraints << current_scope.where_clause.ast
619
+ end
620
+
621
+ dm = Arel::DeleteManager.new(arel_table)
393
622
  dm.wheres = constraints
394
623
 
395
624
  connection.delete(dm, "#{self} Destroy")
396
625
  end
397
626
 
398
627
  private
628
+ def inherited(subclass)
629
+ super
630
+ subclass.class_eval do
631
+ @_query_constraints_list = nil
632
+ @has_query_constraints = false
633
+ end
634
+ end
635
+
399
636
  # Given a class, an attributes hash, +instantiate_instance_of+ returns a
400
637
  # new instance of the class. Accepts only keys as strings.
401
638
  def instantiate_instance_of(klass, attributes, column_types = {}, &block)
@@ -412,12 +649,14 @@ module ActiveRecord
412
649
  self
413
650
  end
414
651
 
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
652
+ # Called by +_update_record+ and +_delete_record+
653
+ # to build `where` clause from default scopes.
654
+ # Skips empty scopes.
655
+ def build_default_constraint
656
+ return unless default_scopes?(all_queries: true)
657
+
658
+ default_where_clause = default_scoped(all_queries: true).where_clause
659
+ default_where_clause.ast unless default_where_clause.empty?
421
660
  end
422
661
  end
423
662
 
@@ -428,12 +667,17 @@ module ActiveRecord
428
667
  end
429
668
 
430
669
  # 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
670
+ # update or delete, the object didn't exist in the database and new_record? would have
432
671
  # returned true.
433
672
  def previously_new_record?
434
673
  @previously_new_record
435
674
  end
436
675
 
676
+ # Returns true if this object was previously persisted but now it has been deleted.
677
+ def previously_persisted?
678
+ !new_record? && destroyed?
679
+ end
680
+
437
681
  # Returns true if this object has been destroyed, otherwise returns false.
438
682
  def destroyed?
439
683
  @destroyed
@@ -522,6 +766,7 @@ module ActiveRecord
522
766
  def delete
523
767
  _delete_row if persisted?
524
768
  @destroyed = true
769
+ @previously_new_record = false
525
770
  freeze
526
771
  end
527
772
 
@@ -535,12 +780,9 @@ module ActiveRecord
535
780
  def destroy
536
781
  _raise_readonly_record_error if readonly?
537
782
  destroy_associations
538
- @_trigger_destroy_callback = if persisted?
539
- destroy_row > 0
540
- else
541
- true
542
- end
783
+ @_trigger_destroy_callback ||= persisted? && destroy_row > 0
543
784
  @destroyed = true
785
+ @previously_new_record = false
544
786
  freeze
545
787
  end
546
788
 
@@ -556,21 +798,24 @@ module ActiveRecord
556
798
  end
557
799
 
558
800
  # 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
801
+ # current record. This is mostly useful in relation to single table
802
+ # inheritance (STI) structures where you want a subclass to appear as the
561
803
  # superclass. This can be used along with record identification in
562
804
  # Action Pack to allow, say, <tt>Client < Company</tt> to do something
563
805
  # like render <tt>partial: @client.becomes(Company)</tt> to render that
564
806
  # instance using the companies/company partial instead of clients/client.
565
807
  #
566
808
  # 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.
809
+ # Therefore the STI column value will still be the same.
568
810
  # 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.
811
+ # This includes any attribute initialization done by the new instance.
812
+ #
813
+ # If you want to change the STI column as well, use #becomes! instead.
570
814
  def becomes(klass)
571
815
  became = klass.allocate
572
816
 
573
817
  became.send(:initialize) do |becoming|
818
+ @attributes.reverse_merge!(becoming.instance_variable_get(:@attributes))
574
819
  becoming.instance_variable_set(:@attributes, @attributes)
575
820
  becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
576
821
  becoming.instance_variable_set(:@new_record, new_record?)
@@ -581,11 +826,11 @@ module ActiveRecord
581
826
  became
582
827
  end
583
828
 
584
- # Wrapper around #becomes that also changes the instance's sti column value.
829
+ # Wrapper around #becomes that also changes the instance's STI column value.
585
830
  # This is especially useful if you want to persist the changed class in your
586
831
  # database.
587
832
  #
588
- # Note: The old instance's sti column value will be changed too, as both objects
833
+ # Note: The old instance's STI column value will be changed too, as both objects
589
834
  # share the same set of attributes.
590
835
  def becomes!(klass)
591
836
  became = becomes(klass)
@@ -605,7 +850,7 @@ module ActiveRecord
605
850
  # * updated_at/updated_on column is updated if that column is available.
606
851
  # * Updates all the attributes that are dirty in this object.
607
852
  #
608
- # This method raises an ActiveRecord::ActiveRecordError if the
853
+ # This method raises an ActiveRecord::ActiveRecordError if the
609
854
  # attribute is marked as readonly.
610
855
  #
611
856
  # Also see #update_column.
@@ -617,6 +862,28 @@ module ActiveRecord
617
862
  save(validate: false)
618
863
  end
619
864
 
865
+ # Updates a single attribute and saves the record.
866
+ # This is especially useful for boolean flags on existing records. Also note that
867
+ #
868
+ # * Validation is skipped.
869
+ # * \Callbacks are invoked.
870
+ # * updated_at/updated_on column is updated if that column is available.
871
+ # * Updates all the attributes that are dirty in this object.
872
+ #
873
+ # This method raises an ActiveRecord::ActiveRecordError if the
874
+ # attribute is marked as readonly.
875
+ #
876
+ # If any of the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
877
+ # and #update_attribute! raises ActiveRecord::RecordNotSaved. See
878
+ # ActiveRecord::Callbacks for further details.
879
+ def update_attribute!(name, value)
880
+ name = name.to_s
881
+ verify_readonly_attribute(name)
882
+ public_send("#{name}=", value)
883
+
884
+ save!(validate: false)
885
+ end
886
+
620
887
  # Updates the attributes of the model from the passed-in hash and saves the
621
888
  # record, all wrapped in a transaction. If the object is invalid, the saving
622
889
  # will fail and false will be returned.
@@ -664,6 +931,7 @@ module ActiveRecord
664
931
  def update_columns(attributes)
665
932
  raise ActiveRecordError, "cannot update a new record" if new_record?
666
933
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
934
+ _raise_readonly_record_error if readonly?
667
935
 
668
936
  attributes = attributes.transform_keys do |key|
669
937
  name = key.to_s
@@ -671,14 +939,15 @@ module ActiveRecord
671
939
  verify_readonly_attribute(name) || name
672
940
  end
673
941
 
674
- id_in_database = self.id_in_database
675
- attributes.each do |k, v|
676
- write_attribute_without_type_cast(k, v)
942
+ update_constraints = _query_constraints_hash
943
+ attributes = attributes.each_with_object({}) do |(k, v), h|
944
+ h[k] = @attributes.write_cast_value(k, v)
945
+ clear_attribute_change(k)
677
946
  end
678
947
 
679
948
  affected_rows = self.class._update_record(
680
949
  attributes,
681
- @primary_key => id_in_database
950
+ update_constraints
682
951
  )
683
952
 
684
953
  affected_rows == 1
@@ -800,13 +1069,13 @@ module ActiveRecord
800
1069
  def reload(options = nil)
801
1070
  self.class.connection.clear_query_cache
802
1071
 
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
1072
+ fresh_object = if apply_scoping?(options)
1073
+ _find_record((options || {}).merge(all_queries: true))
1074
+ else
1075
+ self.class.unscoped { _find_record(options) }
1076
+ end
809
1077
 
1078
+ @association_cache = fresh_object.instance_variable_get(:@association_cache)
810
1079
  @attributes = fresh_object.instance_variable_get(:@attributes)
811
1080
  @new_record = false
812
1081
  @previously_new_record = false
@@ -849,12 +1118,15 @@ module ActiveRecord
849
1118
  #
850
1119
  def touch(*names, time: nil)
851
1120
  _raise_record_not_touched_error unless persisted?
1121
+ _raise_readonly_record_error if readonly?
852
1122
 
853
1123
  attribute_names = timestamp_attributes_for_update_in_model
854
- attribute_names |= names.map! do |name|
1124
+ attribute_names = (attribute_names | names).map! do |name|
855
1125
  name = name.to_s
856
- self.class.attribute_aliases[name] || name
857
- end unless names.empty?
1126
+ name = self.class.attribute_aliases[name] || name
1127
+ verify_readonly_attribute(name)
1128
+ name
1129
+ end
858
1130
 
859
1131
  unless attribute_names.empty?
860
1132
  affected_rows = _touch_row(attribute_names, time)
@@ -865,6 +1137,54 @@ module ActiveRecord
865
1137
  end
866
1138
 
867
1139
  private
1140
+ def init_internals
1141
+ super
1142
+ @_trigger_destroy_callback = @_trigger_update_callback = nil
1143
+ @previously_new_record = false
1144
+ end
1145
+
1146
+ def strict_loaded_associations
1147
+ @association_cache.find_all do |_, assoc|
1148
+ assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
1149
+ end.map(&:first)
1150
+ end
1151
+
1152
+ def _find_record(options)
1153
+ all_queries = options ? options[:all_queries] : nil
1154
+ base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
1155
+
1156
+ if options && options[:lock]
1157
+ base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
1158
+ else
1159
+ base.find_by!(_in_memory_query_constraints_hash)
1160
+ end
1161
+ end
1162
+
1163
+ def _in_memory_query_constraints_hash
1164
+ if self.class.query_constraints_list.nil?
1165
+ { @primary_key => id }
1166
+ else
1167
+ self.class.query_constraints_list.index_with do |column_name|
1168
+ attribute(column_name)
1169
+ end
1170
+ end
1171
+ end
1172
+
1173
+ def apply_scoping?(options)
1174
+ !(options && options[:unscoped]) &&
1175
+ (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
1176
+ end
1177
+
1178
+ def _query_constraints_hash
1179
+ if self.class.query_constraints_list.nil?
1180
+ { @primary_key => id_in_database }
1181
+ else
1182
+ self.class.query_constraints_list.index_with do |column_name|
1183
+ attribute_in_database(column_name)
1184
+ end
1185
+ end
1186
+ end
1187
+
868
1188
  # A hook to be overridden by association modules.
869
1189
  def destroy_associations
870
1190
  end
@@ -874,7 +1194,7 @@ module ActiveRecord
874
1194
  end
875
1195
 
876
1196
  def _delete_row
877
- self.class._delete_record(@primary_key => id_in_database)
1197
+ self.class._delete_record(_query_constraints_hash)
878
1198
  end
879
1199
 
880
1200
  def _touch_row(attribute_names, time)
@@ -890,7 +1210,7 @@ module ActiveRecord
890
1210
  def _update_row(attribute_names, attempted_action = "update")
891
1211
  self.class._update_record(
892
1212
  attributes_with_values(attribute_names),
893
- @primary_key => id_in_database
1213
+ _query_constraints_hash
894
1214
  )
895
1215
  end
896
1216
 
@@ -926,11 +1246,16 @@ module ActiveRecord
926
1246
  def _create_record(attribute_names = self.attribute_names)
927
1247
  attribute_names = attributes_for_create(attribute_names)
928
1248
 
929
- new_id = self.class._insert_record(
930
- attributes_with_values(attribute_names)
1249
+ returning_columns = self.class._returning_columns_for_insert
1250
+
1251
+ returning_values = self.class._insert_record(
1252
+ attributes_with_values(attribute_names),
1253
+ returning_columns
931
1254
  )
932
1255
 
933
- self.id ||= new_id if @primary_key
1256
+ returning_columns.zip(returning_values).each do |column, value|
1257
+ _write_attribute(column, value) if !_read_attribute(column)
1258
+ end if returning_values
934
1259
 
935
1260
  @new_record = false
936
1261
  @previously_new_record = true
@@ -946,7 +1271,8 @@ module ActiveRecord
946
1271
 
947
1272
  def _raise_record_not_destroyed
948
1273
  @_association_destroy_exception ||= nil
949
- raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy the record", self)
1274
+ key = self.class.primary_key
1275
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
950
1276
  ensure
951
1277
  @_association_destroy_exception = nil
952
1278
  end
@@ -961,11 +1287,5 @@ module ActiveRecord
961
1287
  persisted?, new_record?, or destroyed? before touching.
962
1288
  MSG
963
1289
  end
964
-
965
- # The name of the method used to touch a +belongs_to+ association when the
966
- # +:touch+ option is used.
967
- def belongs_to_touch_method
968
- :touch
969
- end
970
1290
  end
971
1291
  end