activerecord 7.0.0 → 7.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +515 -1268
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +31 -31
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +16 -13
  7. data/lib/active_record/association_relation.rb +2 -2
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +35 -12
  10. data/lib/active_record/associations/association_scope.rb +16 -9
  11. data/lib/active_record/associations/belongs_to_association.rb +23 -8
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
  13. data/lib/active_record/associations/builder/association.rb +3 -3
  14. data/lib/active_record/associations/builder/belongs_to.rb +22 -8
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  16. data/lib/active_record/associations/builder/has_many.rb +3 -4
  17. data/lib/active_record/associations/builder/has_one.rb +3 -4
  18. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  19. data/lib/active_record/associations/collection_association.rb +28 -17
  20. data/lib/active_record/associations/collection_proxy.rb +36 -13
  21. data/lib/active_record/associations/errors.rb +265 -0
  22. data/lib/active_record/associations/foreign_association.rb +10 -3
  23. data/lib/active_record/associations/has_many_association.rb +28 -18
  24. data/lib/active_record/associations/has_many_through_association.rb +10 -6
  25. data/lib/active_record/associations/has_one_association.rb +10 -3
  26. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  27. data/lib/active_record/associations/join_dependency.rb +18 -14
  28. data/lib/active_record/associations/nested_error.rb +47 -0
  29. data/lib/active_record/associations/preloader/association.rb +33 -8
  30. data/lib/active_record/associations/preloader/branch.rb +7 -1
  31. data/lib/active_record/associations/preloader/through_association.rb +2 -4
  32. data/lib/active_record/associations/preloader.rb +13 -10
  33. data/lib/active_record/associations/singular_association.rb +7 -1
  34. data/lib/active_record/associations/through_association.rb +22 -11
  35. data/lib/active_record/associations.rb +378 -491
  36. data/lib/active_record/attribute_assignment.rb +1 -13
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  38. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  39. data/lib/active_record/attribute_methods/dirty.rb +53 -35
  40. data/lib/active_record/attribute_methods/primary_key.rb +45 -25
  41. data/lib/active_record/attribute_methods/query.rb +28 -16
  42. data/lib/active_record/attribute_methods/read.rb +8 -7
  43. data/lib/active_record/attribute_methods/serialization.rb +153 -70
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -6
  45. data/lib/active_record/attribute_methods/write.rb +6 -6
  46. data/lib/active_record/attribute_methods.rb +153 -40
  47. data/lib/active_record/attributes.rb +63 -48
  48. data/lib/active_record/autosave_association.rb +70 -38
  49. data/lib/active_record/base.rb +12 -8
  50. data/lib/active_record/callbacks.rb +16 -32
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -34
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +124 -132
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +4 -1
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +297 -88
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +160 -45
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +215 -63
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +83 -65
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +163 -29
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +319 -135
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +367 -75
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +512 -126
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +282 -119
  70. data/lib/active_record/connection_adapters/column.rb +9 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +27 -140
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +64 -52
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +101 -68
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -10
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +16 -3
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +101 -48
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
  87. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +4 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +94 -61
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +6 -10
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +151 -2
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +379 -66
  98. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  99. data/lib/active_record/connection_adapters/postgresql_adapter.rb +370 -203
  100. data/lib/active_record/connection_adapters/schema_cache.rb +302 -79
  101. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  102. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +60 -43
  103. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +61 -46
  104. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  106. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  107. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +64 -22
  108. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +321 -110
  109. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  110. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  111. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  112. data/lib/active_record/connection_adapters.rb +124 -1
  113. data/lib/active_record/connection_handling.rb +98 -106
  114. data/lib/active_record/core.rb +220 -177
  115. data/lib/active_record/counter_cache.rb +68 -34
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +8 -2
  117. data/lib/active_record/database_configurations/database_config.rb +26 -5
  118. data/lib/active_record/database_configurations/hash_config.rb +52 -34
  119. data/lib/active_record/database_configurations/url_config.rb +37 -12
  120. data/lib/active_record/database_configurations.rb +88 -35
  121. data/lib/active_record/delegated_type.rb +40 -11
  122. data/lib/active_record/deprecator.rb +7 -0
  123. data/lib/active_record/destroy_association_async_job.rb +3 -1
  124. data/lib/active_record/disable_joins_association_relation.rb +1 -1
  125. data/lib/active_record/dynamic_matchers.rb +2 -2
  126. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  127. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  128. data/lib/active_record/encryption/config.rb +25 -1
  129. data/lib/active_record/encryption/configurable.rb +13 -14
  130. data/lib/active_record/encryption/context.rb +10 -3
  131. data/lib/active_record/encryption/contexts.rb +8 -4
  132. data/lib/active_record/encryption/derived_secret_key_provider.rb +9 -3
  133. data/lib/active_record/encryption/deterministic_key_provider.rb +1 -1
  134. data/lib/active_record/encryption/encryptable_record.rb +47 -25
  135. data/lib/active_record/encryption/encrypted_attribute_type.rb +49 -14
  136. data/lib/active_record/encryption/encryptor.rb +25 -10
  137. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +3 -3
  138. data/lib/active_record/encryption/extended_deterministic_queries.rb +83 -86
  139. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
  140. data/lib/active_record/encryption/key_generator.rb +12 -1
  141. data/lib/active_record/encryption/message.rb +1 -1
  142. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  143. data/lib/active_record/encryption/message_serializer.rb +6 -0
  144. data/lib/active_record/encryption/null_encryptor.rb +4 -0
  145. data/lib/active_record/encryption/properties.rb +4 -4
  146. data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
  147. data/lib/active_record/encryption/scheme.rb +23 -22
  148. data/lib/active_record/encryption.rb +1 -0
  149. data/lib/active_record/enum.rb +131 -27
  150. data/lib/active_record/errors.rb +151 -31
  151. data/lib/active_record/explain.rb +21 -12
  152. data/lib/active_record/explain_subscriber.rb +1 -1
  153. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  154. data/lib/active_record/fixture_set/render_context.rb +2 -0
  155. data/lib/active_record/fixture_set/table_row.rb +29 -8
  156. data/lib/active_record/fixtures.rb +169 -99
  157. data/lib/active_record/future_result.rb +47 -8
  158. data/lib/active_record/gem_version.rb +3 -3
  159. data/lib/active_record/inheritance.rb +34 -18
  160. data/lib/active_record/insert_all.rb +72 -22
  161. data/lib/active_record/integration.rb +13 -10
  162. data/lib/active_record/internal_metadata.rb +124 -20
  163. data/lib/active_record/locking/optimistic.rb +39 -24
  164. data/lib/active_record/locking/pessimistic.rb +8 -5
  165. data/lib/active_record/log_subscriber.rb +28 -27
  166. data/lib/active_record/marshalling.rb +56 -0
  167. data/lib/active_record/message_pack.rb +124 -0
  168. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  169. data/lib/active_record/middleware/database_selector.rb +18 -13
  170. data/lib/active_record/middleware/shard_selector.rb +7 -5
  171. data/lib/active_record/migration/command_recorder.rb +110 -13
  172. data/lib/active_record/migration/compatibility.rb +174 -64
  173. data/lib/active_record/migration/default_strategy.rb +22 -0
  174. data/lib/active_record/migration/execution_strategy.rb +19 -0
  175. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  176. data/lib/active_record/migration.rb +292 -125
  177. data/lib/active_record/model_schema.rb +113 -112
  178. data/lib/active_record/nested_attributes.rb +35 -9
  179. data/lib/active_record/normalization.rb +163 -0
  180. data/lib/active_record/persistence.rb +177 -345
  181. data/lib/active_record/promise.rb +84 -0
  182. data/lib/active_record/query_cache.rb +19 -25
  183. data/lib/active_record/query_logs.rb +102 -51
  184. data/lib/active_record/query_logs_formatter.rb +41 -0
  185. data/lib/active_record/querying.rb +34 -9
  186. data/lib/active_record/railtie.rb +153 -100
  187. data/lib/active_record/railties/controller_runtime.rb +24 -10
  188. data/lib/active_record/railties/databases.rake +148 -152
  189. data/lib/active_record/railties/job_runtime.rb +23 -0
  190. data/lib/active_record/readonly_attributes.rb +32 -5
  191. data/lib/active_record/reflection.rb +278 -69
  192. data/lib/active_record/relation/batches/batch_enumerator.rb +20 -5
  193. data/lib/active_record/relation/batches.rb +198 -63
  194. data/lib/active_record/relation/calculations.rb +293 -108
  195. data/lib/active_record/relation/delegation.rb +31 -20
  196. data/lib/active_record/relation/finder_methods.rb +93 -18
  197. data/lib/active_record/relation/merger.rb +6 -6
  198. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  199. data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
  200. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  201. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  202. data/lib/active_record/relation/predicate_builder.rb +28 -16
  203. data/lib/active_record/relation/query_attribute.rb +25 -1
  204. data/lib/active_record/relation/query_methods.rb +625 -107
  205. data/lib/active_record/relation/record_fetch_warning.rb +3 -0
  206. data/lib/active_record/relation/spawn_methods.rb +5 -4
  207. data/lib/active_record/relation/where_clause.rb +7 -19
  208. data/lib/active_record/relation.rb +602 -96
  209. data/lib/active_record/result.rb +55 -52
  210. data/lib/active_record/runtime_registry.rb +63 -1
  211. data/lib/active_record/sanitization.rb +76 -30
  212. data/lib/active_record/schema.rb +39 -23
  213. data/lib/active_record/schema_dumper.rb +82 -30
  214. data/lib/active_record/schema_migration.rb +75 -24
  215. data/lib/active_record/scoping/default.rb +20 -12
  216. data/lib/active_record/scoping/named.rb +3 -2
  217. data/lib/active_record/scoping.rb +2 -1
  218. data/lib/active_record/secure_password.rb +60 -0
  219. data/lib/active_record/secure_token.rb +21 -3
  220. data/lib/active_record/serialization.rb +5 -0
  221. data/lib/active_record/signed_id.rb +29 -8
  222. data/lib/active_record/statement_cache.rb +7 -7
  223. data/lib/active_record/store.rb +16 -11
  224. data/lib/active_record/suppressor.rb +3 -1
  225. data/lib/active_record/table_metadata.rb +7 -3
  226. data/lib/active_record/tasks/database_tasks.rb +191 -121
  227. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  228. data/lib/active_record/tasks/postgresql_database_tasks.rb +17 -15
  229. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  230. data/lib/active_record/test_fixtures.rb +174 -152
  231. data/lib/active_record/testing/query_assertions.rb +121 -0
  232. data/lib/active_record/timestamp.rb +31 -17
  233. data/lib/active_record/token_for.rb +123 -0
  234. data/lib/active_record/touch_later.rb +12 -7
  235. data/lib/active_record/transaction.rb +132 -0
  236. data/lib/active_record/transactions.rb +109 -27
  237. data/lib/active_record/translation.rb +1 -3
  238. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  239. data/lib/active_record/type/internal/timezone.rb +7 -2
  240. data/lib/active_record/type/serialized.rb +9 -7
  241. data/lib/active_record/type/time.rb +4 -0
  242. data/lib/active_record/type_caster/connection.rb +4 -4
  243. data/lib/active_record/validations/absence.rb +1 -1
  244. data/lib/active_record/validations/associated.rb +12 -6
  245. data/lib/active_record/validations/numericality.rb +5 -4
  246. data/lib/active_record/validations/presence.rb +5 -28
  247. data/lib/active_record/validations/uniqueness.rb +63 -14
  248. data/lib/active_record/validations.rb +12 -5
  249. data/lib/active_record/version.rb +1 -1
  250. data/lib/active_record.rb +266 -30
  251. data/lib/arel/alias_predication.rb +1 -1
  252. data/lib/arel/collectors/bind.rb +2 -0
  253. data/lib/arel/collectors/composite.rb +7 -0
  254. data/lib/arel/collectors/sql_string.rb +1 -1
  255. data/lib/arel/collectors/substitute_binds.rb +1 -1
  256. data/lib/arel/errors.rb +10 -0
  257. data/lib/arel/factory_methods.rb +4 -0
  258. data/lib/arel/filter_predications.rb +1 -1
  259. data/lib/arel/nodes/binary.rb +6 -7
  260. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  261. data/lib/arel/nodes/cte.rb +36 -0
  262. data/lib/arel/nodes/filter.rb +1 -1
  263. data/lib/arel/nodes/fragments.rb +35 -0
  264. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  265. data/lib/arel/nodes/leading_join.rb +8 -0
  266. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  267. data/lib/arel/nodes/node.rb +115 -5
  268. data/lib/arel/nodes/sql_literal.rb +13 -0
  269. data/lib/arel/nodes/table_alias.rb +4 -0
  270. data/lib/arel/nodes.rb +6 -2
  271. data/lib/arel/predications.rb +3 -1
  272. data/lib/arel/select_manager.rb +1 -1
  273. data/lib/arel/table.rb +9 -5
  274. data/lib/arel/tree_manager.rb +8 -3
  275. data/lib/arel/update_manager.rb +2 -1
  276. data/lib/arel/visitors/dot.rb +1 -0
  277. data/lib/arel/visitors/mysql.rb +17 -5
  278. data/lib/arel/visitors/postgresql.rb +1 -12
  279. data/lib/arel/visitors/to_sql.rb +112 -34
  280. data/lib/arel/visitors/visitor.rb +2 -2
  281. data/lib/arel.rb +21 -3
  282. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  283. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  284. data/lib/rails/generators/active_record/migration.rb +3 -1
  285. data/lib/rails/generators/active_record/model/USAGE +113 -0
  286. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  287. metadata +59 -17
  288. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  289. data/lib/active_record/null_relation.rb +0 -63
@@ -57,281 +57,34 @@ module ActiveRecord
57
57
  end
58
58
  end
59
59
 
60
- # Inserts a single record into the database in a single SQL INSERT
61
- # statement. It does not instantiate any models nor does it trigger
62
- # Active Record callbacks or validations. Though passed values
63
- # go through Active Record's type casting and serialization.
60
+ # Builds an object (or multiple objects) and returns either the built object or a list of built
61
+ # objects.
64
62
  #
65
- # See <tt>ActiveRecord::Persistence#insert_all</tt> 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
- end
69
-
70
- # Inserts multiple records into the database in a single SQL INSERT
71
- # statement. It does not instantiate any models nor does it trigger
72
- # Active Record callbacks or validations. Though passed values
73
- # go through Active Record's type casting and serialization.
74
- #
75
- # The +attributes+ parameter is an Array of Hashes. Every Hash determines
76
- # the attributes for a single row and must have the same keys.
77
- #
78
- # Rows are considered to be unique by every unique index on the table. Any
79
- # duplicate rows are skipped.
80
- # Override with <tt>:unique_by</tt> (see below).
81
- #
82
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
83
- # <tt>:returning</tt> (see below).
84
- #
85
- # ==== Options
86
- #
87
- # [:returning]
88
- # (PostgreSQL only) An array of attributes to return for all successfully
89
- # inserted records, which by default is the primary key.
90
- # Pass <tt>returning: %w[ id name ]</tt> for both id and name
91
- # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
92
- # clause entirely.
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
- #
97
- # [:unique_by]
98
- # (PostgreSQL and SQLite only) By default rows are considered to be unique
99
- # by every unique index on the table. Any duplicate rows are skipped.
100
- #
101
- # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
102
- #
103
- # Consider a Book model where no duplicate ISBNs make sense, but if any
104
- # row has an existing id, or is not unique by another unique index,
105
- # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
106
- #
107
- # Unique indexes can be identified by columns or name:
108
- #
109
- # unique_by: :isbn
110
- # unique_by: %i[ author_id name ]
111
- # unique_by: :index_books_on_isbn
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
- #
124
- # Because it relies on the index information from the database
125
- # <tt>:unique_by</tt> is recommended to be paired with
126
- # Active Record's schema_cache.
127
- #
128
- # ==== Example
129
- #
130
- # # Insert records and skip inserting any duplicates.
131
- # # Here "Eloquent Ruby" is skipped because its id is not unique.
132
- #
133
- # Book.insert_all([
134
- # { id: 1, title: "Rework", author: "David" },
135
- # { id: 1, title: "Eloquent Ruby", author: "Russ" }
136
- # ])
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
147
- end
148
-
149
- # Inserts a single record into the database in a single SQL INSERT
150
- # statement. It does not instantiate any models nor does it trigger
151
- # Active Record callbacks or validations. Though passed values
152
- # go through Active Record's type casting and serialization.
153
- #
154
- # See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
155
- def insert!(attributes, returning: nil, record_timestamps: nil)
156
- insert_all!([ attributes ], returning: returning, record_timestamps: record_timestamps)
157
- end
158
-
159
- # Inserts multiple records into the database in a single SQL INSERT
160
- # statement. It does not instantiate any models nor does it trigger
161
- # Active Record callbacks or validations. Though passed values
162
- # go through Active Record's type casting and serialization.
163
- #
164
- # The +attributes+ parameter is an Array of Hashes. Every Hash determines
165
- # the attributes for a single row and must have the same keys.
166
- #
167
- # Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
168
- # unique index on the table. In that case, no rows are inserted.
169
- #
170
- # To skip duplicate rows, see <tt>ActiveRecord::Persistence#insert_all</tt>.
171
- # To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
172
- #
173
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
174
- # <tt>:returning</tt> (see below).
175
- #
176
- # ==== Options
177
- #
178
- # [:returning]
179
- # (PostgreSQL only) An array of attributes to return for all successfully
180
- # inserted records, which by default is the primary key.
181
- # Pass <tt>returning: %w[ id name ]</tt> for both id and name
182
- # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
183
- # clause entirely.
184
- #
185
- # You can also pass an SQL string if you need more control on the return values
186
- # (for example, <tt>returning: "id, name as new_name"</tt>).
187
- #
188
- # [:record_timestamps]
189
- # By default, automatic setting of timestamp columns is controlled by
190
- # the model's <tt>record_timestamps</tt> config, matching typical
191
- # behavior.
192
- #
193
- # To override this and force automatic setting of timestamp columns one
194
- # way or the other, pass <tt>:record_timestamps</tt>:
195
- #
196
- # record_timestamps: true # Always set timestamps automatically
197
- # record_timestamps: false # Never set timestamps automatically
198
- #
199
- # ==== Examples
200
- #
201
- # # Insert multiple records
202
- # Book.insert_all!([
203
- # { title: "Rework", author: "David" },
204
- # { title: "Eloquent Ruby", author: "Russ" }
205
- # ])
206
- #
207
- # # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
208
- # # does not have a unique id.
209
- # Book.insert_all!([
210
- # { id: 1, title: "Rework", author: "David" },
211
- # { id: 1, title: "Eloquent Ruby", author: "Russ" }
212
- # ])
213
- def insert_all!(attributes, returning: nil, record_timestamps: nil)
214
- InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning, record_timestamps: record_timestamps).execute
215
- end
216
-
217
- # Updates or inserts (upserts) a single record into the database in a
218
- # single SQL INSERT statement. It does not instantiate any models nor does
219
- # it trigger Active Record callbacks or validations. Though passed values
220
- # go through Active Record's type casting and serialization.
221
- #
222
- # See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
223
- def upsert(attributes, on_duplicate: :update, returning: nil, unique_by: nil, record_timestamps: nil)
224
- upsert_all([ attributes ], on_duplicate: on_duplicate, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps)
225
- end
226
-
227
- # Updates or inserts (upserts) multiple records into the database in a
228
- # single SQL INSERT statement. It does not instantiate any models nor does
229
- # it trigger Active Record callbacks or validations. Though passed values
230
- # go through Active Record's type casting and serialization.
231
- #
232
- # The +attributes+ parameter is an Array of Hashes. Every Hash determines
233
- # the attributes for a single row and must have the same keys.
234
- #
235
- # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
236
- # <tt>:returning</tt> (see below).
237
- #
238
- # By default, +upsert_all+ will update all the columns that can be updated when
239
- # there is a conflict. These are all the columns except primary keys, read-only
240
- # columns, and columns covered by the optional +unique_by+.
241
- #
242
- # ==== Options
243
- #
244
- # [:returning]
245
- # (PostgreSQL only) An array of attributes to return for all successfully
246
- # inserted records, which by default is the primary key.
247
- # Pass <tt>returning: %w[ id name ]</tt> for both id and name
248
- # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
249
- # clause entirely.
250
- #
251
- # You can also pass an SQL string if you need more control on the return values
252
- # (for example, <tt>returning: "id, name as new_name"</tt>).
253
- #
254
- # [:unique_by]
255
- # (PostgreSQL and SQLite only) By default rows are considered to be unique
256
- # by every unique index on the table. Any duplicate rows are skipped.
257
- #
258
- # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
259
- #
260
- # Consider a Book model where no duplicate ISBNs make sense, but if any
261
- # row has an existing id, or is not unique by another unique index,
262
- # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
263
- #
264
- # Unique indexes can be identified by columns or name:
265
- #
266
- # unique_by: :isbn
267
- # unique_by: %i[ author_id name ]
268
- # unique_by: :index_books_on_isbn
269
- #
270
- # Because it relies on the index information from the database
271
- # <tt>:unique_by</tt> is recommended to be paired with
272
- # Active Record's schema_cache.
273
- #
274
- # [:on_duplicate]
275
- # Configure the SQL update sentence that will be used in case of conflict.
276
- #
277
- # NOTE: If you use this option you must provide all the columns you want to update
278
- # by yourself.
279
- #
280
- # Example:
281
- #
282
- # Commodity.upsert_all(
283
- # [
284
- # { id: 2, name: "Copper", price: 4.84 },
285
- # { id: 4, name: "Gold", price: 1380.87 },
286
- # { id: 6, name: "Aluminium", price: 0.35 }
287
- # ],
288
- # on_duplicate: Arel.sql("price = GREATEST(commodities.price, EXCLUDED.price)")
289
- # )
290
- #
291
- # See the related +:update_only+ option. Both options can't be used at the same time.
292
- #
293
- # [:update_only]
294
- # Provide a list of column names that will be updated in case of conflict. If not provided,
295
- # +upsert_all+ will update all the columns that can be updated. These are all the columns
296
- # except primary keys, read-only columns, and columns covered by the optional +unique_by+
297
- #
298
- # Example:
299
- #
300
- # Commodity.upsert_all(
301
- # [
302
- # { id: 2, name: "Copper", price: 4.84 },
303
- # { id: 4, name: "Gold", price: 1380.87 },
304
- # { id: 6, name: "Aluminium", price: 0.35 }
305
- # ],
306
- # update_only: [:price] # Only prices will be updated
307
- # )
308
- #
309
- # See the related +:on_duplicate+ option. Both options can't be used at the same time.
310
- #
311
- # [:record_timestamps]
312
- # By default, automatic setting of timestamp columns is controlled by
313
- # the model's <tt>record_timestamps</tt> config, matching typical
314
- # behavior.
315
- #
316
- # To override this and force automatic setting of timestamp columns one
317
- # way or the other, pass <tt>:record_timestamps</tt>:
318
- #
319
- # record_timestamps: true # Always set timestamps automatically
320
- # record_timestamps: false # Never set timestamps automatically
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.
321
65
  #
322
66
  # ==== Examples
67
+ # # Build a single new object
68
+ # User.build(first_name: 'Jamie')
323
69
  #
324
- # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
325
- # # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
70
+ # # Build an Array of new objects
71
+ # User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
326
72
  #
327
- # Book.upsert_all([
328
- # { title: "Rework", author: "David", isbn: "1" },
329
- # { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
330
- # ], unique_by: :isbn)
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
331
77
  #
332
- # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
333
- def upsert_all(attributes, on_duplicate: :update, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
334
- InsertAll.new(self, attributes, on_duplicate: on_duplicate, update_only: update_only, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps).execute
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
335
88
  end
336
89
 
337
90
  # Given an attributes hash, +instantiate+ returns a new instance of
@@ -426,56 +179,63 @@ module ActiveRecord
426
179
  end
427
180
  end
428
181
 
429
- # Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
430
- # therefore all callbacks and filters are fired off before the object is deleted. This method is
431
- # less efficient than #delete but allows cleanup methods and other actions to be run.
182
+ # Accepts a list of attribute names to be used in the WHERE clause
183
+ # of SELECT / UPDATE / DELETE queries and in the ORDER BY clause for +#first+ and +#last+ finder methods.
184
+ #
185
+ # class Developer < ActiveRecord::Base
186
+ # query_constraints :company_id, :id
187
+ # end
432
188
  #
433
- # This essentially finds the object (or multiple objects) with the given id, creates a new object
434
- # from the attributes, and then calls destroy on it.
189
+ # developer = Developer.first
190
+ # # SELECT "developers".* FROM "developers" ORDER BY "developers"."company_id" ASC, "developers"."id" ASC LIMIT 1
191
+ # developer.inspect # => #<Developer id: 1, company_id: 1, ...>
435
192
  #
436
- # ==== Parameters
193
+ # developer.update!(name: "Nikita")
194
+ # # UPDATE "developers" SET "name" = 'Nikita' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
437
195
  #
438
- # * +id+ - This should be the id or an array of ids to be destroyed.
196
+ # # It is possible to update an attribute used in the query_constraints clause:
197
+ # developer.update!(company_id: 2)
198
+ # # UPDATE "developers" SET "company_id" = 2 WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
439
199
  #
440
- # ==== Examples
200
+ # developer.name = "Bob"
201
+ # developer.save!
202
+ # # UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
441
203
  #
442
- # # Destroy a single object
443
- # Todo.destroy(1)
204
+ # developer.destroy!
205
+ # # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
444
206
  #
445
- # # Destroy multiple objects
446
- # todos = [1,2,3]
447
- # Todo.destroy(todos)
448
- def destroy(id)
449
- if id.is_a?(Array)
450
- find(id).each(&:destroy)
207
+ # developer.delete
208
+ # # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
209
+ #
210
+ # developer.reload
211
+ # # SELECT "developers".* FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1 LIMIT 1
212
+ def query_constraints(*columns_list)
213
+ raise ArgumentError, "You must specify at least one column to be used in querying" if columns_list.empty?
214
+
215
+ @query_constraints_list = columns_list.map(&:to_s)
216
+ @has_query_constraints = @query_constraints_list
217
+ end
218
+
219
+ def has_query_constraints? # :nodoc:
220
+ @has_query_constraints
221
+ end
222
+
223
+ def query_constraints_list # :nodoc:
224
+ @query_constraints_list ||= if base_class? || primary_key != base_class.primary_key
225
+ primary_key if primary_key.is_a?(Array)
451
226
  else
452
- find(id).destroy
227
+ base_class.query_constraints_list
453
228
  end
454
229
  end
455
230
 
456
- # Deletes the row with a primary key matching the +id+ argument, using an
457
- # SQL +DELETE+ statement, and returns the number of rows deleted. Active
458
- # Record objects are not instantiated, so the object's callbacks are not
459
- # executed, including any <tt>:dependent</tt> association options.
460
- #
461
- # You can delete multiple rows at once by passing an Array of <tt>id</tt>s.
462
- #
463
- # Note: Although it is often much faster than the alternative, #destroy,
464
- # skipping callbacks might bypass business logic in your application
465
- # that ensures referential integrity or performs other essential jobs.
466
- #
467
- # ==== Examples
468
- #
469
- # # Delete a single row
470
- # Todo.delete(1)
471
- #
472
- # # Delete multiple rows
473
- # Todo.delete([2,3,4])
474
- def delete(id_or_array)
475
- delete_by(primary_key => id_or_array)
231
+ # Returns an array of column names to be used in queries. The source of column
232
+ # names is derived from +query_constraints_list+ or +primary_key+. This method
233
+ # is for internal use when the primary key is to be treated as an array.
234
+ def composite_query_constraints_list # :nodoc:
235
+ @composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
476
236
  end
477
237
 
478
- def _insert_record(values) # :nodoc:
238
+ def _insert_record(connection, values, returning) # :nodoc:
479
239
  primary_key = self.primary_key
480
240
  primary_key_value = nil
481
241
 
@@ -488,13 +248,18 @@ module ActiveRecord
488
248
 
489
249
  im = Arel::InsertManager.new(arel_table)
490
250
 
491
- if values.empty?
492
- im.insert(connection.empty_insert_statement_value(primary_key))
493
- else
494
- im.insert(values.transform_keys { |name| arel_table[name] })
495
- end
251
+ with_connection do |c|
252
+ if values.empty?
253
+ im.insert(connection.empty_insert_statement_value(primary_key))
254
+ else
255
+ im.insert(values.transform_keys { |name| arel_table[name] })
256
+ end
496
257
 
497
- connection.insert(im, "#{self} Create", primary_key || false, primary_key_value)
258
+ connection.insert(
259
+ im, "#{self} Create", primary_key || false, primary_key_value,
260
+ returning: returning
261
+ )
262
+ end
498
263
  end
499
264
 
500
265
  def _update_record(values, constraints) # :nodoc:
@@ -511,7 +276,9 @@ module ActiveRecord
511
276
  um.set(values.transform_keys { |name| arel_table[name] })
512
277
  um.wheres = constraints
513
278
 
514
- connection.update(um, "#{self} Update")
279
+ with_connection do |c|
280
+ c.update(um, "#{self} Update")
281
+ end
515
282
  end
516
283
 
517
284
  def _delete_record(constraints) # :nodoc:
@@ -527,10 +294,20 @@ module ActiveRecord
527
294
  dm = Arel::DeleteManager.new(arel_table)
528
295
  dm.wheres = constraints
529
296
 
530
- connection.delete(dm, "#{self} Destroy")
297
+ with_connection do |c|
298
+ c.delete(dm, "#{self} Destroy")
299
+ end
531
300
  end
532
301
 
533
302
  private
303
+ def inherited(subclass)
304
+ super
305
+ subclass.class_eval do
306
+ @_query_constraints_list = nil
307
+ @has_query_constraints = false
308
+ end
309
+ end
310
+
534
311
  # Given a class, an attributes hash, +instantiate_instance_of+ returns a
535
312
  # new instance of the class. Accepts only keys as strings.
536
313
  def instantiate_instance_of(klass, attributes, column_types = {}, &block)
@@ -565,7 +342,7 @@ module ActiveRecord
565
342
  end
566
343
 
567
344
  # Returns true if this object was just created -- that is, prior to the last
568
- # save, the object didn't exist in the database and new_record? would have
345
+ # update or delete, the object didn't exist in the database and new_record? would have
569
346
  # returned true.
570
347
  def previously_new_record?
571
348
  @previously_new_record
@@ -664,6 +441,7 @@ module ActiveRecord
664
441
  def delete
665
442
  _delete_row if persisted?
666
443
  @destroyed = true
444
+ @previously_new_record = false
667
445
  freeze
668
446
  end
669
447
 
@@ -677,12 +455,9 @@ module ActiveRecord
677
455
  def destroy
678
456
  _raise_readonly_record_error if readonly?
679
457
  destroy_associations
680
- @_trigger_destroy_callback = if persisted?
681
- destroy_row > 0
682
- else
683
- true
684
- end
458
+ @_trigger_destroy_callback ||= persisted? && destroy_row > 0
685
459
  @destroyed = true
460
+ @previously_new_record = false
686
461
  freeze
687
462
  end
688
463
 
@@ -708,11 +483,14 @@ module ActiveRecord
708
483
  # Note: The new instance will share a link to the same attributes as the original class.
709
484
  # Therefore the STI column value will still be the same.
710
485
  # Any change to the attributes on either instance will affect both instances.
486
+ # This includes any attribute initialization done by the new instance.
487
+ #
711
488
  # If you want to change the STI column as well, use #becomes! instead.
712
489
  def becomes(klass)
713
490
  became = klass.allocate
714
491
 
715
492
  became.send(:initialize) do |becoming|
493
+ @attributes.reverse_merge!(becoming.instance_variable_get(:@attributes))
716
494
  becoming.instance_variable_set(:@attributes, @attributes)
717
495
  becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
718
496
  becoming.instance_variable_set(:@new_record, new_record?)
@@ -747,7 +525,7 @@ module ActiveRecord
747
525
  # * updated_at/updated_on column is updated if that column is available.
748
526
  # * Updates all the attributes that are dirty in this object.
749
527
  #
750
- # This method raises an ActiveRecord::ActiveRecordError if the
528
+ # This method raises an ActiveRecord::ActiveRecordError if the
751
529
  # attribute is marked as readonly.
752
530
  #
753
531
  # Also see #update_column.
@@ -759,6 +537,28 @@ module ActiveRecord
759
537
  save(validate: false)
760
538
  end
761
539
 
540
+ # Updates a single attribute and saves the record.
541
+ # This is especially useful for boolean flags on existing records. Also note that
542
+ #
543
+ # * Validation is skipped.
544
+ # * \Callbacks are invoked.
545
+ # * updated_at/updated_on column is updated if that column is available.
546
+ # * Updates all the attributes that are dirty in this object.
547
+ #
548
+ # This method raises an ActiveRecord::ActiveRecordError if the
549
+ # attribute is marked as readonly.
550
+ #
551
+ # If any of the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
552
+ # and #update_attribute! raises ActiveRecord::RecordNotSaved. See
553
+ # ActiveRecord::Callbacks for further details.
554
+ def update_attribute!(name, value)
555
+ name = name.to_s
556
+ verify_readonly_attribute(name)
557
+ public_send("#{name}=", value)
558
+
559
+ save!(validate: false)
560
+ end
561
+
762
562
  # Updates the attributes of the model from the passed-in hash and saves the
763
563
  # record, all wrapped in a transaction. If the object is invalid, the saving
764
564
  # will fail and false will be returned.
@@ -806,6 +606,7 @@ module ActiveRecord
806
606
  def update_columns(attributes)
807
607
  raise ActiveRecordError, "cannot update a new record" if new_record?
808
608
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
609
+ _raise_readonly_record_error if readonly?
809
610
 
810
611
  attributes = attributes.transform_keys do |key|
811
612
  name = key.to_s
@@ -813,7 +614,7 @@ module ActiveRecord
813
614
  verify_readonly_attribute(name) || name
814
615
  end
815
616
 
816
- update_constraints = _primary_key_constraints_hash
617
+ update_constraints = _query_constraints_hash
817
618
  attributes = attributes.each_with_object({}) do |(k, v), h|
818
619
  h[k] = @attributes.write_cast_value(k, v)
819
620
  clear_attribute_change(k)
@@ -941,15 +742,16 @@ module ActiveRecord
941
742
  # end
942
743
  #
943
744
  def reload(options = nil)
944
- self.class.connection.clear_query_cache
745
+ self.class.connection_pool.clear_query_cache
945
746
 
946
747
  fresh_object = if apply_scoping?(options)
947
- _find_record(options)
748
+ _find_record((options || {}).merge(all_queries: true))
948
749
  else
949
750
  self.class.unscoped { _find_record(options) }
950
751
  end
951
752
 
952
753
  @association_cache = fresh_object.instance_variable_get(:@association_cache)
754
+ @association_cache.each_value { |association| association.owner = self }
953
755
  @attributes = fresh_object.instance_variable_get(:@attributes)
954
756
  @new_record = false
955
757
  @previously_new_record = false
@@ -992,12 +794,15 @@ module ActiveRecord
992
794
  #
993
795
  def touch(*names, time: nil)
994
796
  _raise_record_not_touched_error unless persisted?
797
+ _raise_readonly_record_error if readonly?
995
798
 
996
799
  attribute_names = timestamp_attributes_for_update_in_model
997
- attribute_names |= names.map! do |name|
800
+ attribute_names = (attribute_names | names).map! do |name|
998
801
  name = name.to_s
999
- self.class.attribute_aliases[name] || name
1000
- end unless names.empty?
802
+ name = self.class.attribute_aliases[name] || name
803
+ verify_readonly_attribute(name)
804
+ name
805
+ end
1001
806
 
1002
807
  unless attribute_names.empty?
1003
808
  affected_rows = _touch_row(attribute_names, time)
@@ -1008,6 +813,12 @@ module ActiveRecord
1008
813
  end
1009
814
 
1010
815
  private
816
+ def init_internals
817
+ super
818
+ @_trigger_destroy_callback = @_trigger_update_callback = nil
819
+ @previously_new_record = false
820
+ end
821
+
1011
822
  def strict_loaded_associations
1012
823
  @association_cache.find_all do |_, assoc|
1013
824
  assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
@@ -1015,10 +826,23 @@ module ActiveRecord
1015
826
  end
1016
827
 
1017
828
  def _find_record(options)
829
+ all_queries = options ? options[:all_queries] : nil
830
+ base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
831
+
1018
832
  if options && options[:lock]
1019
- self.class.preload(strict_loaded_associations).lock(options[:lock]).find(id)
833
+ base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
834
+ else
835
+ base.find_by!(_in_memory_query_constraints_hash)
836
+ end
837
+ end
838
+
839
+ def _in_memory_query_constraints_hash
840
+ if self.class.query_constraints_list.nil?
841
+ { @primary_key => id }
1020
842
  else
1021
- self.class.preload(strict_loaded_associations).find(id)
843
+ self.class.query_constraints_list.index_with do |column_name|
844
+ attribute(column_name)
845
+ end
1022
846
  end
1023
847
  end
1024
848
 
@@ -1027,8 +851,14 @@ module ActiveRecord
1027
851
  (self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
1028
852
  end
1029
853
 
1030
- def _primary_key_constraints_hash
1031
- { @primary_key => id_in_database }
854
+ def _query_constraints_hash
855
+ if self.class.query_constraints_list.nil?
856
+ { @primary_key => id_in_database }
857
+ else
858
+ self.class.query_constraints_list.index_with do |column_name|
859
+ attribute_in_database(column_name)
860
+ end
861
+ end
1032
862
  end
1033
863
 
1034
864
  # A hook to be overridden by association modules.
@@ -1040,7 +870,7 @@ module ActiveRecord
1040
870
  end
1041
871
 
1042
872
  def _delete_row
1043
- self.class._delete_record(_primary_key_constraints_hash)
873
+ self.class._delete_record(_query_constraints_hash)
1044
874
  end
1045
875
 
1046
876
  def _touch_row(attribute_names, time)
@@ -1056,7 +886,7 @@ module ActiveRecord
1056
886
  def _update_row(attribute_names, attempted_action = "update")
1057
887
  self.class._update_record(
1058
888
  attributes_with_values(attribute_names),
1059
- _primary_key_constraints_hash
889
+ _query_constraints_hash
1060
890
  )
1061
891
  end
1062
892
 
@@ -1092,11 +922,19 @@ module ActiveRecord
1092
922
  def _create_record(attribute_names = self.attribute_names)
1093
923
  attribute_names = attributes_for_create(attribute_names)
1094
924
 
1095
- new_id = self.class._insert_record(
1096
- attributes_with_values(attribute_names)
1097
- )
925
+ self.class.with_connection do |connection|
926
+ returning_columns = self.class._returning_columns_for_insert(connection)
1098
927
 
1099
- self.id ||= new_id if @primary_key
928
+ returning_values = self.class._insert_record(
929
+ connection,
930
+ attributes_with_values(attribute_names),
931
+ returning_columns
932
+ )
933
+
934
+ returning_columns.zip(returning_values).each do |column, value|
935
+ _write_attribute(column, value) if !_read_attribute(column)
936
+ end if returning_values
937
+ end
1100
938
 
1101
939
  @new_record = false
1102
940
  @previously_new_record = true
@@ -1113,7 +951,7 @@ module ActiveRecord
1113
951
  def _raise_record_not_destroyed
1114
952
  @_association_destroy_exception ||= nil
1115
953
  key = self.class.primary_key
1116
- raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{send(key)}", self)
954
+ raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
1117
955
  ensure
1118
956
  @_association_destroy_exception = nil
1119
957
  end
@@ -1128,11 +966,5 @@ module ActiveRecord
1128
966
  persisted?, new_record?, or destroyed? before touching.
1129
967
  MSG
1130
968
  end
1131
-
1132
- # The name of the method used to touch a +belongs_to+ association when the
1133
- # +:touch+ option is used.
1134
- def belongs_to_touch_method
1135
- :touch
1136
- end
1137
969
  end
1138
970
  end