activerecord 6.1.7 → 7.1.5

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 (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  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 +51 -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 +39 -35
  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/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  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 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  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 +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  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/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -6,6 +6,13 @@ module ActiveRecord
6
6
  module ModelSchema
7
7
  extend ActiveSupport::Concern
8
8
 
9
+ ##
10
+ # :method: id_value
11
+ # :call-seq: id_value
12
+ #
13
+ # Returns the underlying column value for a column named "id". Useful when defining
14
+ # a composite primary key including an "id" column so that the value is readable.
15
+
9
16
  ##
10
17
  # :singleton-method: primary_key_prefix_type
11
18
  # :call-seq: primary_key_prefix_type
@@ -126,9 +133,29 @@ module ActiveRecord
126
133
  # +:immutable_string+. This setting does not affect the behavior of
127
134
  # <tt>attribute :foo, :string</tt>. Defaults to false.
128
135
 
129
- included do
130
- mattr_accessor :primary_key_prefix_type, instance_writer: false
136
+ ##
137
+ # :singleton-method: inheritance_column
138
+ # :call-seq: inheritance_column
139
+ #
140
+ # The name of the table column which stores the class name on single-table
141
+ # inheritance situations.
142
+ #
143
+ # The default inheritance column name is +type+, which means it's a
144
+ # reserved word inside Active Record. To be able to use single-table
145
+ # inheritance with another column name, or to use the column +type+ in
146
+ # your own model for something else, you can set +inheritance_column+:
147
+ #
148
+ # self.inheritance_column = 'zoink'
149
+
150
+ ##
151
+ # :singleton-method: inheritance_column=
152
+ # :call-seq: inheritance_column=(column)
153
+ #
154
+ # Defines the name of the table column which will store the class name on single-table
155
+ # inheritance situations.
131
156
 
157
+ included do
158
+ class_attribute :primary_key_prefix_type, instance_writer: false
132
159
  class_attribute :table_name_prefix, instance_writer: false, default: ""
133
160
  class_attribute :table_name_suffix, instance_writer: false, default: ""
134
161
  class_attribute :schema_migrations_table_name, instance_accessor: false, default: "schema_migrations"
@@ -137,8 +164,15 @@ module ActiveRecord
137
164
  class_attribute :implicit_order_column, instance_accessor: false
138
165
  class_attribute :immutable_strings_by_default, instance_accessor: false
139
166
 
167
+ class_attribute :inheritance_column, instance_accessor: false, default: "type"
168
+ singleton_class.class_eval do
169
+ alias_method :_inheritance_column=, :inheritance_column=
170
+ private :_inheritance_column=
171
+ alias_method :inheritance_column=, :real_inheritance_column=
172
+ end
173
+
140
174
  self.protected_environments = ["production"]
141
- self.inheritance_column = "type"
175
+
142
176
  self.ignored_columns = [].freeze
143
177
 
144
178
  delegate :type_for_attribute, :column_for_attribute, to: :class
@@ -153,8 +187,9 @@ module ActiveRecord
153
187
  # artists, records => artists_records
154
188
  # records, artists => artists_records
155
189
  # music_artists, music_records => music_artists_records
190
+ # music.artists, music.records => music.artists_records
156
191
  def self.derive_join_table_name(first_table, second_table) # :nodoc:
157
- [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
192
+ [first_table.to_s, second_table.to_s].sort.join("\0").gsub(/^(.*[_.])(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
158
193
  end
159
194
 
160
195
  module ClassMethods
@@ -197,6 +232,21 @@ module ActiveRecord
197
232
  # the table name guess for an Invoice class becomes "myapp_invoices".
198
233
  # Invoice::Lineitem becomes "myapp_invoice_lineitems".
199
234
  #
235
+ # Active Model Naming's +model_name+ is the base name used to guess the
236
+ # table name. In case a custom Active Model Name is defined, it will be
237
+ # used for the table name as well:
238
+ #
239
+ # class PostRecord < ActiveRecord::Base
240
+ # class << self
241
+ # def model_name
242
+ # ActiveModel::Name.new(self, nil, "Post")
243
+ # end
244
+ # end
245
+ # end
246
+ #
247
+ # PostRecord.table_name
248
+ # # => "posts"
249
+ #
200
250
  # You can also set your own table name explicitly:
201
251
  #
202
252
  # class Mouse < ActiveRecord::Base
@@ -233,9 +283,11 @@ module ActiveRecord
233
283
  end
234
284
 
235
285
  # Computes the table name, (re)sets it internally, and returns it.
236
- def reset_table_name #:nodoc:
237
- self.table_name = if abstract_class?
238
- superclass == Base ? nil : superclass.table_name
286
+ def reset_table_name # :nodoc:
287
+ self.table_name = if self == Base
288
+ nil
289
+ elsif abstract_class?
290
+ superclass.table_name
239
291
  elsif superclass.abstract_class?
240
292
  superclass.table_name || compute_table_name
241
293
  else
@@ -243,11 +295,11 @@ module ActiveRecord
243
295
  end
244
296
  end
245
297
 
246
- def full_table_name_prefix #:nodoc:
298
+ def full_table_name_prefix # :nodoc:
247
299
  (module_parents.detect { |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
248
300
  end
249
301
 
250
- def full_table_name_suffix #:nodoc:
302
+ def full_table_name_suffix # :nodoc:
251
303
  (module_parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
252
304
  end
253
305
 
@@ -266,33 +318,14 @@ module ActiveRecord
266
318
  @protected_environments = environments.map(&:to_s)
267
319
  end
268
320
 
269
- # Defines the name of the table column which will store the class name on single-table
270
- # inheritance situations.
271
- #
272
- # The default inheritance column name is +type+, which means it's a
273
- # reserved word inside Active Record. To be able to use single-table
274
- # inheritance with another column name, or to use the column +type+ in
275
- # your own model for something else, you can set +inheritance_column+:
276
- #
277
- # self.inheritance_column = 'zoink'
278
- def inheritance_column
279
- (@inheritance_column ||= nil) || superclass.inheritance_column
280
- end
281
-
282
- # Sets the value of inheritance_column
283
- def inheritance_column=(value)
284
- @inheritance_column = value.to_s
285
- @explicit_inheritance_column = true
321
+ def real_inheritance_column=(value) # :nodoc:
322
+ self._inheritance_column = value.to_s
286
323
  end
287
324
 
288
325
  # The list of columns names the model should ignore. Ignored columns won't have attribute
289
326
  # accessors defined, and won't be referenced in SQL queries.
290
327
  def ignored_columns
291
- if defined?(@ignored_columns)
292
- @ignored_columns
293
- else
294
- superclass.ignored_columns
295
- end
328
+ @ignored_columns || superclass.ignored_columns
296
329
  end
297
330
 
298
331
  # Sets the columns names the model should ignore. Ignored columns won't have attribute
@@ -313,7 +346,7 @@ module ActiveRecord
313
346
  # # name :string, limit: 255
314
347
  # # category :string, limit: 255
315
348
  #
316
- # self.ignored_columns = [:category]
349
+ # self.ignored_columns += [:category]
317
350
  # end
318
351
  #
319
352
  # The schema still contains "category", but now the model omits it, so any meta-driven code or
@@ -339,7 +372,7 @@ module ActiveRecord
339
372
  end
340
373
  end
341
374
 
342
- def reset_sequence_name #:nodoc:
375
+ def reset_sequence_name # :nodoc:
343
376
  @explicit_sequence_name = false
344
377
  @sequence_name = connection.default_sequence_name(table_name, primary_key)
345
378
  end
@@ -398,6 +431,16 @@ module ActiveRecord
398
431
  @columns ||= columns_hash.values.freeze
399
432
  end
400
433
 
434
+ def _returning_columns_for_insert # :nodoc:
435
+ @_returning_columns_for_insert ||= begin
436
+ auto_populated_columns = columns.filter_map do |c|
437
+ c.name if connection.return_value_after_insert?(c)
438
+ end
439
+
440
+ auto_populated_columns.empty? ? Array(primary_key) : auto_populated_columns
441
+ end
442
+ end
443
+
401
444
  def attribute_types # :nodoc:
402
445
  load_schema
403
446
  @attribute_types ||= Hash.new(Type.default_value)
@@ -430,7 +473,7 @@ module ActiveRecord
430
473
  end
431
474
 
432
475
  # Returns the column object for the named attribute.
433
- # Returns an +ActiveRecord::ConnectionAdapters::NullColumn+ if the
476
+ # Returns an ActiveRecord::ConnectionAdapters::NullColumn if the
434
477
  # named attribute does not exist.
435
478
  #
436
479
  # class Person < ActiveRecord::Base
@@ -486,9 +529,9 @@ module ActiveRecord
486
529
  #
487
530
  # The most common usage pattern for this method is probably in a migration,
488
531
  # when just after creating a table you want to populate it with some default
489
- # values, eg:
532
+ # values, e.g.:
490
533
  #
491
- # class CreateJobLevels < ActiveRecord::Migration[6.0]
534
+ # class CreateJobLevels < ActiveRecord::Migration[7.1]
492
535
  # def up
493
536
  # create_table :job_levels do |t|
494
537
  # t.integer :id
@@ -516,35 +559,61 @@ module ActiveRecord
516
559
  initialize_find_by_cache
517
560
  end
518
561
 
562
+ def load_schema # :nodoc:
563
+ return if schema_loaded?
564
+ @load_schema_monitor.synchronize do
565
+ return if @columns_hash
566
+
567
+ load_schema!
568
+
569
+ @schema_loaded = true
570
+ rescue
571
+ reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
572
+ raise
573
+ end
574
+ end
575
+
519
576
  protected
520
577
  def initialize_load_schema_monitor
521
578
  @load_schema_monitor = Monitor.new
522
579
  end
523
580
 
581
+ def reload_schema_from_cache(recursive = true)
582
+ @_returning_columns_for_insert = nil
583
+ @arel_table = nil
584
+ @column_names = nil
585
+ @symbol_column_to_string_name_hash = nil
586
+ @attribute_types = nil
587
+ @content_columns = nil
588
+ @default_attributes = nil
589
+ @column_defaults = nil
590
+ @attributes_builder = nil
591
+ @columns = nil
592
+ @columns_hash = nil
593
+ @schema_loaded = false
594
+ @attribute_names = nil
595
+ @yaml_encoder = nil
596
+ if recursive
597
+ subclasses.each do |descendant|
598
+ descendant.send(:reload_schema_from_cache)
599
+ end
600
+ end
601
+ end
602
+
524
603
  private
525
604
  def inherited(child_class)
526
605
  super
527
606
  child_class.initialize_load_schema_monitor
607
+ child_class.reload_schema_from_cache(false)
608
+ child_class.class_eval do
609
+ @ignored_columns = nil
610
+ end
528
611
  end
529
612
 
530
613
  def schema_loaded?
531
614
  defined?(@schema_loaded) && @schema_loaded
532
615
  end
533
616
 
534
- def load_schema
535
- return if schema_loaded?
536
- @load_schema_monitor.synchronize do
537
- return if defined?(@columns_hash) && @columns_hash
538
-
539
- load_schema!
540
-
541
- @schema_loaded = true
542
- rescue
543
- reload_schema_from_cache # If the schema loading failed half way through, we must reset the state.
544
- raise
545
- end
546
- end
547
-
548
617
  def load_schema!
549
618
  unless table_name
550
619
  raise ActiveRecord::TableNotSpecified, "#{self} has no table configured. Set one with #{self}.table_name="
@@ -556,39 +625,20 @@ module ActiveRecord
556
625
  @columns_hash.each do |name, column|
557
626
  type = connection.lookup_cast_type_from_column(column)
558
627
  type = _convert_type_from_options(type)
559
- warn_if_deprecated_type(column)
560
628
  define_attribute(
561
629
  name,
562
630
  type,
563
631
  default: column.default,
564
632
  user_provided_default: false
565
633
  )
634
+ alias_attribute :id_value, :id if name == "id"
566
635
  end
567
- end
568
-
569
- def reload_schema_from_cache
570
- @arel_table = nil
571
- @column_names = nil
572
- @symbol_column_to_string_name_hash = nil
573
- @attribute_types = nil
574
- @content_columns = nil
575
- @default_attributes = nil
576
- @column_defaults = nil
577
- @inheritance_column = nil unless defined?(@explicit_inheritance_column) && @explicit_inheritance_column
578
- @attributes_builder = nil
579
- @columns = nil
580
- @columns_hash = nil
581
- @schema_loaded = false
582
- @attribute_names = nil
583
- @yaml_encoder = nil
584
- direct_descendants.each do |descendant|
585
- descendant.send(:reload_schema_from_cache)
586
- end
636
+ _default_attributes # Precompute to cache DB-dependent attribute types
587
637
  end
588
638
 
589
639
  # Guesses the table name, but does not decorate it with prefix and suffix information.
590
- def undecorated_table_name(class_name = base_class.name)
591
- table_name = class_name.to_s.demodulize.underscore
640
+ def undecorated_table_name(model_name)
641
+ table_name = model_name.to_s.demodulize.underscore
592
642
  pluralize_table_names ? table_name.pluralize : table_name
593
643
  end
594
644
 
@@ -602,9 +652,9 @@ module ActiveRecord
602
652
  contained += "_"
603
653
  end
604
654
 
605
- "#{full_table_name_prefix}#{contained}#{undecorated_table_name(name)}#{full_table_name_suffix}"
655
+ "#{full_table_name_prefix}#{contained}#{undecorated_table_name(model_name)}#{full_table_name_suffix}"
606
656
  else
607
- # STI subclasses always use their superclass' table.
657
+ # STI subclasses always use their superclass's table.
608
658
  base_class.table_name
609
659
  end
610
660
  end
@@ -616,32 +666,6 @@ module ActiveRecord
616
666
  type
617
667
  end
618
668
  end
619
-
620
- def warn_if_deprecated_type(column)
621
- return if attributes_to_define_after_schema_loads.key?(column.name)
622
- return unless column.respond_to?(:oid)
623
-
624
- if column.array?
625
- array_arguments = ", array: true"
626
- else
627
- array_arguments = ""
628
- end
629
-
630
- if column.sql_type.start_with?("interval")
631
- precision_arguments = column.precision.presence && ", precision: #{column.precision}"
632
- ActiveSupport::Deprecation.warn(<<~WARNING)
633
- The behavior of the `:interval` type will be changing in Rails 7.0
634
- to return an `ActiveSupport::Duration` object. If you'd like to keep
635
- the old behavior, you can add this line to #{self.name} model:
636
-
637
- attribute :#{column.name}, :string#{precision_arguments}#{array_arguments}
638
-
639
- If you'd like the new behavior today, you can add this line:
640
-
641
- attribute :#{column.name}, :interval#{precision_arguments}#{array_arguments}
642
- WARNING
643
- end
644
- end
645
669
  end
646
670
  end
647
671
  end
@@ -5,7 +5,7 @@ require "active_support/core_ext/module/redefine_method"
5
5
  require "active_support/core_ext/hash/indifferent_access"
6
6
 
7
7
  module ActiveRecord
8
- module NestedAttributes #:nodoc:
8
+ module NestedAttributes # :nodoc:
9
9
  class TooManyRecords < ActiveRecordError
10
10
  end
11
11
 
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  class_attribute :nested_attributes_options, instance_writer: false, default: {}
16
16
  end
17
17
 
18
- # = Active Record Nested Attributes
18
+ # = Active Record Nested \Attributes
19
19
  #
20
20
  # Nested attributes allow you to save attributes on associated records
21
21
  # through the parent. By default nested attribute updating is turned off
@@ -180,7 +180,7 @@ module ActiveRecord
180
180
  # member.posts.second.title # => '[UPDATED] other post'
181
181
  #
182
182
  # However, the above applies if the parent model is being updated as well.
183
- # For example, If you wanted to create a +member+ named _joe_ and wanted to
183
+ # For example, if you wanted to create a +member+ named _joe_ and wanted to
184
184
  # update the +posts+ at the same time, that would give an
185
185
  # ActiveRecord::RecordNotFound error.
186
186
  #
@@ -245,18 +245,19 @@ module ActiveRecord
245
245
  #
246
246
  # === Validating the presence of a parent model
247
247
  #
248
- # If you want to validate that a child record is associated with a parent
249
- # record, you can use the +validates_presence_of+ method and the +:inverse_of+
250
- # key as this example illustrates:
248
+ # The +belongs_to+ association validates the presence of the parent model
249
+ # by default. You can disable this behavior by specifying <code>optional: true</code>.
250
+ # This can be used, for example, when conditionally validating the presence
251
+ # of the parent model:
251
252
  #
252
- # class Member < ActiveRecord::Base
253
- # has_many :posts, inverse_of: :member
254
- # accepts_nested_attributes_for :posts
253
+ # class Veterinarian < ActiveRecord::Base
254
+ # has_many :patients, inverse_of: :veterinarian
255
+ # accepts_nested_attributes_for :patients
255
256
  # end
256
257
  #
257
- # class Post < ActiveRecord::Base
258
- # belongs_to :member, inverse_of: :posts
259
- # validates_presence_of :member
258
+ # class Patient < ActiveRecord::Base
259
+ # belongs_to :veterinarian, inverse_of: :patients, optional: true
260
+ # validates :veterinarian, presence: true, unless: -> { awaiting_intake }
260
261
  # end
261
262
  #
262
263
  # Note that if you do not specify the +:inverse_of+ option, then
@@ -279,6 +280,24 @@ module ActiveRecord
279
280
  # member = Member.new
280
281
  # member.avatar_attributes = {icon: 'sad'}
281
282
  # member.avatar.width # => 200
283
+ #
284
+ # === Creating forms with nested attributes
285
+ #
286
+ # Use ActionView::Helpers::FormHelper#fields_for to create form elements for
287
+ # nested attributes.
288
+ #
289
+ # Integration test params should reflect the structure of the form. For
290
+ # example:
291
+ #
292
+ # post members_path, params: {
293
+ # member: {
294
+ # name: 'joe',
295
+ # posts_attributes: {
296
+ # '0' => { title: 'Foo' },
297
+ # '1' => { title: 'Bar' }
298
+ # }
299
+ # }
300
+ # }
282
301
  module ClassMethods
283
302
  REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } }
284
303
 
@@ -288,7 +307,7 @@ module ActiveRecord
288
307
  # [:allow_destroy]
289
308
  # If true, destroys any members from the attributes hash with a
290
309
  # <tt>_destroy</tt> key and a value that evaluates to +true+
291
- # (e.g. 1, '1', true, or 'true'). This option is off by default.
310
+ # (e.g. 1, '1', true, or 'true'). This option is false by default.
292
311
  # [:reject_if]
293
312
  # Allows you to specify a Proc or a Symbol pointing to a method
294
313
  # that checks whether a record should be built for a certain attribute
@@ -313,11 +332,11 @@ module ActiveRecord
313
332
  # nested attributes are going to be used when an associated record already
314
333
  # exists. In general, an existing record may either be updated with the
315
334
  # new set of attribute values or be replaced by a wholly new record
316
- # containing those values. By default the +:update_only+ option is +false+
335
+ # containing those values. By default the +:update_only+ option is false
317
336
  # and the nested attributes are used to update the existing record only
318
337
  # if they include the record's <tt>:id</tt> value. Otherwise a new
319
338
  # record will be instantiated and used to replace the existing one.
320
- # However if the +:update_only+ option is +true+, the nested attributes
339
+ # However if the +:update_only+ option is true, the nested attributes
321
340
  # are used to update the record's attributes always, regardless of
322
341
  # whether the <tt>:id</tt> is present. The option is ignored for collection
323
342
  # associations.
@@ -374,11 +393,11 @@ module ActiveRecord
374
393
  end
375
394
  end
376
395
 
377
- # Returns ActiveRecord::AutosaveAssociation::marked_for_destruction? It's
396
+ # Returns ActiveRecord::AutosaveAssociation#marked_for_destruction? It's
378
397
  # used in conjunction with fields_for to build a form element for the
379
398
  # destruction of this association.
380
399
  #
381
- # See ActionView::Helpers::FormHelper::fields_for for more info.
400
+ # See ActionView::Helpers::FormHelper#fields_for for more info.
382
401
  def _destroy
383
402
  marked_for_destruction?
384
403
  end
@@ -486,7 +505,7 @@ module ActiveRecord
486
505
  existing_records = if association.loaded?
487
506
  association.target
488
507
  else
489
- attribute_ids = attributes_collection.map { |a| a["id"] || a[:id] }.compact
508
+ attribute_ids = attributes_collection.filter_map { |a| a["id"] || a[:id] }
490
509
  attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids)
491
510
  end
492
511
 
@@ -500,12 +519,12 @@ module ActiveRecord
500
519
  unless reject_new_record?(association_name, attributes)
501
520
  association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
502
521
  end
503
- elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
522
+ elsif existing_record = find_record_by_id(existing_records, attributes["id"])
504
523
  unless call_reject_if(association_name, attributes)
505
524
  # Make sure we are operating on the actual object which is in the association's
506
525
  # proxy_target array (either by finding it, or adding it if not found)
507
526
  # Take into account that the proxy_target may have changed due to callbacks
508
- target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s }
527
+ target_record = find_record_by_id(association.target, attributes["id"])
509
528
  if target_record
510
529
  existing_record = target_record
511
530
  else
@@ -593,5 +612,16 @@ module ActiveRecord
593
612
  raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
594
613
  model, "id", record_id)
595
614
  end
615
+
616
+ def find_record_by_id(records, id)
617
+ return if records.empty?
618
+
619
+ if records.first.class.composite_primary_key?
620
+ id = Array(id).map(&:to_s)
621
+ records.find { |record| Array(record.id).map(&:to_s) == id }
622
+ else
623
+ records.find { |record| record.id.to_s == id.to_s }
624
+ end
625
+ end
596
626
  end
597
627
  end
@@ -26,20 +26,20 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  class << self
29
- def apply_to(klass) #:nodoc:
29
+ def apply_to(klass) # :nodoc:
30
30
  klasses.push(klass)
31
31
  yield
32
32
  ensure
33
33
  klasses.pop
34
34
  end
35
35
 
36
- def applied_to?(klass) #:nodoc:
36
+ def applied_to?(klass) # :nodoc:
37
37
  klasses.any? { |k| k >= klass }
38
38
  end
39
39
 
40
40
  private
41
41
  def klasses
42
- Thread.current[:no_touching_classes] ||= []
42
+ ActiveSupport::IsolatedExecutionState[:active_record_no_touching_classes] ||= []
43
43
  end
44
44
  end
45
45