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
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- # Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt>
4
+ # Returns the currently loaded version of Active Record as a +Gem::Version+.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
8
8
 
9
9
  module VERSION
10
- MAJOR = 6
10
+ MAJOR = 7
11
11
  MINOR = 1
12
- TINY = 7
12
+ TINY = 5
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/inflector"
3
4
  require "active_support/core_ext/hash/indifferent_access"
4
5
 
5
6
  module ActiveRecord
6
- # == Single table inheritance
7
+ # = Single table inheritance
7
8
  #
8
9
  # Active Record allows inheritance by storing the name of the class in a column that by
9
10
  # default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
@@ -31,8 +32,9 @@ module ActiveRecord
31
32
  # be triggered. In that case, it'll work just like normal subclasses with no special magic
32
33
  # for differentiating between them or reloading the right type with find.
33
34
  #
34
- # Note, all the attributes for all the cases are kept in the same table. Read more:
35
- # https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
35
+ # Note, all the attributes for all the cases are kept in the same table.
36
+ # Read more:
37
+ # * https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
36
38
  #
37
39
  module Inheritance
38
40
  extend ActiveSupport::Concern
@@ -43,6 +45,8 @@ module ActiveRecord
43
45
  # Determines whether to store the full constant name including namespace when using STI.
44
46
  # This is true, by default.
45
47
  class_attribute :store_full_sti_class, instance_writer: false, default: true
48
+
49
+ set_base_class
46
50
  end
47
51
 
48
52
  module ClassMethods
@@ -85,30 +89,30 @@ module ActiveRecord
85
89
  end
86
90
  end
87
91
 
88
- def finder_needs_type_condition? #:nodoc:
92
+ def finder_needs_type_condition? # :nodoc:
89
93
  # This is like this because benchmarking justifies the strange :false stuff
90
94
  :true == (@finder_needs_type_condition ||= descends_from_active_record? ? :false : :true)
91
95
  end
92
96
 
93
- # Returns the class descending directly from ActiveRecord::Base, or
94
- # an abstract class, if any, in the inheritance hierarchy.
97
+ # Returns the first class in the inheritance hierarchy that descends from either an
98
+ # abstract class or from <tt>ActiveRecord::Base</tt>.
95
99
  #
96
- # If A extends ActiveRecord::Base, A.base_class will return A. If B descends from A
97
- # through some arbitrarily deep hierarchy, B.base_class will return A.
100
+ # Consider the following behaviour:
98
101
  #
99
- # If B < A and C < B and if A is an abstract_class then both B.base_class
100
- # and C.base_class would return B as the answer since A is an abstract_class.
101
- def base_class
102
- unless self < Base
103
- raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
104
- end
105
-
106
- if superclass == Base || superclass.abstract_class?
107
- self
108
- else
109
- superclass.base_class
110
- end
111
- end
102
+ # class ApplicationRecord < ActiveRecord::Base
103
+ # self.abstract_class = true
104
+ # end
105
+ # class Shape < ApplicationRecord
106
+ # self.abstract_class = true
107
+ # end
108
+ # Polygon = Class.new(Shape)
109
+ # Square = Class.new(Polygon)
110
+ #
111
+ # ApplicationRecord.base_class # => ApplicationRecord
112
+ # Shape.base_class # => Shape
113
+ # Polygon.base_class # => Polygon
114
+ # Square.base_class # => Polygon
115
+ attr_reader :base_class
112
116
 
113
117
  # Returns whether the class is a base class.
114
118
  # See #base_class for more information.
@@ -123,7 +127,7 @@ module ActiveRecord
123
127
  # true.
124
128
  # +ApplicationRecord+, for example, is generated as an abstract class.
125
129
  #
126
- # Consider the following default behaviour:
130
+ # Consider the following default behavior:
127
131
  #
128
132
  # Shape = Class.new(ActiveRecord::Base)
129
133
  # Polygon = Class.new(Shape)
@@ -164,6 +168,21 @@ module ActiveRecord
164
168
  defined?(@abstract_class) && @abstract_class == true
165
169
  end
166
170
 
171
+ # Sets the application record class for Active Record
172
+ #
173
+ # This is useful if your application uses a different class than
174
+ # ApplicationRecord for your primary abstract class. This class
175
+ # will share a database connection with Active Record. It is the class
176
+ # that connects to your primary database.
177
+ def primary_abstract_class
178
+ if ActiveRecord.application_record_class && ActiveRecord.application_record_class.name != name
179
+ raise ArgumentError, "The `primary_abstract_class` is already set to #{ActiveRecord.application_record_class.inspect}. There can only be one `primary_abstract_class` in an application."
180
+ end
181
+
182
+ self.abstract_class = true
183
+ ActiveRecord.application_record_class = self
184
+ end
185
+
167
186
  # Returns the value to be stored in the inheritance column for STI.
168
187
  def sti_name
169
188
  store_full_sti_class && store_full_class_name ? name : name.demodulize
@@ -174,7 +193,7 @@ module ActiveRecord
174
193
  # It is used to find the class correspondent to the value stored in the inheritance column.
175
194
  def sti_class_for(type_name)
176
195
  if store_full_sti_class && store_full_class_name
177
- ActiveSupport::Dependencies.constantize(type_name)
196
+ type_name.constantize
178
197
  else
179
198
  compute_type(type_name)
180
199
  end
@@ -196,15 +215,23 @@ module ActiveRecord
196
215
  # It is used to find the class correspondent to the value stored in the polymorphic type column.
197
216
  def polymorphic_class_for(name)
198
217
  if store_full_class_name
199
- ActiveSupport::Dependencies.constantize(name)
218
+ name.constantize
200
219
  else
201
220
  compute_type(name)
202
221
  end
203
222
  end
204
223
 
205
- def inherited(subclass)
206
- subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
224
+ def dup # :nodoc:
225
+ # `initialize_dup` / `initialize_copy` don't work when defined
226
+ # in the `singleton_class`.
227
+ other = super
228
+ other.set_base_class
229
+ other
230
+ end
231
+
232
+ def initialize_clone(other) # :nodoc:
207
233
  super
234
+ set_base_class
208
235
  end
209
236
 
210
237
  protected
@@ -214,10 +241,10 @@ module ActiveRecord
214
241
  if type_name.start_with?("::")
215
242
  # If the type is prefixed with a scope operator then we assume that
216
243
  # the type_name is an absolute reference.
217
- ActiveSupport::Dependencies.constantize(type_name)
244
+ type_name.constantize
218
245
  else
219
246
  type_candidate = @_type_candidates_cache[type_name]
220
- if type_candidate && type_constant = ActiveSupport::Dependencies.safe_constantize(type_candidate)
247
+ if type_candidate && type_constant = type_candidate.safe_constantize
221
248
  return type_constant
222
249
  end
223
250
 
@@ -227,7 +254,7 @@ module ActiveRecord
227
254
  candidates << type_name
228
255
 
229
256
  candidates.each do |candidate|
230
- constant = ActiveSupport::Dependencies.safe_constantize(candidate)
257
+ constant = candidate.safe_constantize
231
258
  if candidate == constant.to_s
232
259
  @_type_candidates_cache[type_name] = candidate
233
260
  return constant
@@ -238,7 +265,32 @@ module ActiveRecord
238
265
  end
239
266
  end
240
267
 
268
+ def set_base_class # :nodoc:
269
+ @base_class = if self == Base
270
+ self
271
+ else
272
+ unless self < Base
273
+ raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
274
+ end
275
+
276
+ if superclass == Base || superclass.abstract_class?
277
+ self
278
+ else
279
+ superclass.base_class
280
+ end
281
+ end
282
+ end
283
+
241
284
  private
285
+ def inherited(subclass)
286
+ super
287
+ subclass.set_base_class
288
+ subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
289
+ subclass.class_eval do
290
+ @finder_needs_type_condition = nil
291
+ end
292
+ end
293
+
242
294
  # Called by +instantiate+ to decide which class to use for a new
243
295
  # record instance. For single-table inheritance, we check the record
244
296
  # for a +type+ column and return the corresponding class.
@@ -5,13 +5,23 @@ require "active_support/core_ext/enumerable"
5
5
  module ActiveRecord
6
6
  class InsertAll # :nodoc:
7
7
  attr_reader :model, :connection, :inserts, :keys
8
- attr_reader :on_duplicate, :returning, :unique_by
9
-
10
- def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
11
- raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
12
-
13
- @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
14
- @on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
8
+ attr_reader :on_duplicate, :update_only, :returning, :unique_by, :update_sql
9
+
10
+ def initialize(model, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
11
+ @model, @connection, @inserts = model, model.connection, inserts.map(&:stringify_keys)
12
+ @on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
13
+ @record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
14
+
15
+ disallow_raw_sql!(on_duplicate)
16
+ disallow_raw_sql!(returning)
17
+
18
+ if @inserts.empty?
19
+ @keys = []
20
+ else
21
+ resolve_sti
22
+ resolve_attribute_aliases
23
+ @keys = @inserts.first.keys
24
+ end
15
25
 
16
26
  if model.scope_attributes?
17
27
  @scope_attributes = model.scope_attributes
@@ -22,13 +32,15 @@ module ActiveRecord
22
32
  @returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
23
33
  @returning = false if @returning == []
24
34
 
25
- @unique_by = find_unique_index_for(unique_by)
26
- @on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
35
+ @unique_by = find_unique_index_for(@unique_by)
27
36
 
37
+ configure_on_duplicate_update_logic
28
38
  ensure_valid_options_for_connection!
29
39
  end
30
40
 
31
41
  def execute
42
+ return ActiveRecord::Result.empty if inserts.empty?
43
+
32
44
  message = +"#{model} "
33
45
  message << "Bulk " if inserts.many?
34
46
  message << (on_duplicate == :update ? "Upsert" : "Insert")
@@ -36,7 +48,7 @@ module ActiveRecord
36
48
  end
37
49
 
38
50
  def updatable_columns
39
- keys - readonly_columns - unique_by_columns
51
+ @updatable_columns ||= keys - readonly_columns - unique_by_columns
40
52
  end
41
53
 
42
54
  def primary_keys
@@ -56,18 +68,80 @@ module ActiveRecord
56
68
  inserts.map do |attributes|
57
69
  attributes = attributes.stringify_keys
58
70
  attributes.merge!(scope_attributes) if scope_attributes
71
+ attributes.reverse_merge!(timestamps_for_create) if record_timestamps?
59
72
 
60
73
  verify_attributes(attributes)
61
74
 
62
- keys.map do |key|
75
+ keys_including_timestamps.map do |key|
63
76
  yield key, attributes[key]
64
77
  end
65
78
  end
66
79
  end
67
80
 
81
+ def record_timestamps?
82
+ @record_timestamps
83
+ end
84
+
85
+ # TODO: Consider renaming this method, as it only conditionally extends keys, not always
86
+ def keys_including_timestamps
87
+ @keys_including_timestamps ||= if record_timestamps?
88
+ keys + model.all_timestamp_attributes_in_model
89
+ else
90
+ keys
91
+ end
92
+ end
93
+
68
94
  private
69
95
  attr_reader :scope_attributes
70
96
 
97
+ def has_attribute_aliases?(attributes)
98
+ attributes.keys.any? { |attribute| model.attribute_alias?(attribute) }
99
+ end
100
+
101
+ def resolve_sti
102
+ return if model.descends_from_active_record?
103
+
104
+ sti_type = model.sti_name
105
+ @inserts = @inserts.map do |insert|
106
+ insert.reverse_merge(model.inheritance_column.to_s => sti_type)
107
+ end
108
+ end
109
+
110
+ def resolve_attribute_aliases
111
+ return unless has_attribute_aliases?(@inserts.first)
112
+
113
+ @inserts = @inserts.map do |insert|
114
+ insert.transform_keys { |attribute| resolve_attribute_alias(attribute) }
115
+ end
116
+
117
+ @update_only = Array(@update_only).map { |attribute| resolve_attribute_alias(attribute) } if @update_only
118
+ @unique_by = Array(@unique_by).map { |attribute| resolve_attribute_alias(attribute) } if @unique_by
119
+ end
120
+
121
+ def resolve_attribute_alias(attribute)
122
+ model.attribute_alias(attribute) || attribute
123
+ end
124
+
125
+ def configure_on_duplicate_update_logic
126
+ if custom_update_sql_provided? && update_only.present?
127
+ raise ArgumentError, "You can't set :update_only and provide custom update SQL via :on_duplicate at the same time"
128
+ end
129
+
130
+ if update_only.present?
131
+ @updatable_columns = Array(update_only)
132
+ @on_duplicate = :update
133
+ elsif custom_update_sql_provided?
134
+ @update_sql = on_duplicate
135
+ @on_duplicate = :update
136
+ elsif @on_duplicate == :update && updatable_columns.empty?
137
+ @on_duplicate = :skip
138
+ end
139
+ end
140
+
141
+ def custom_update_sql_provided?
142
+ @custom_update_sql_provided ||= Arel.arel_node?(on_duplicate)
143
+ end
144
+
71
145
  def find_unique_index_for(unique_by)
72
146
  if !connection.supports_insert_conflict_target?
73
147
  return if unique_by.nil?
@@ -77,8 +151,9 @@ module ActiveRecord
77
151
 
78
152
  name_or_columns = unique_by || model.primary_key
79
153
  match = Array(name_or_columns).map(&:to_s)
154
+ sorted_match = match.sort
80
155
 
81
- if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
156
+ if index = unique_indexes.find { |i| match.include?(i.name) || Array(i.columns).sort == sorted_match }
82
157
  index
83
158
  elsif match == primary_keys
84
159
  unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
@@ -126,15 +201,28 @@ module ActiveRecord
126
201
 
127
202
 
128
203
  def verify_attributes(attributes)
129
- if keys != attributes.keys.to_set
204
+ if keys_including_timestamps != attributes.keys.to_set
130
205
  raise ArgumentError, "All objects being inserted must have the same keys"
131
206
  end
132
207
  end
133
208
 
209
+ def disallow_raw_sql!(value)
210
+ return if !value.is_a?(String) || Arel.arel_node?(value)
211
+
212
+ raise ArgumentError, "Dangerous query method (method whose arguments are used as raw " \
213
+ "SQL) called: #{value}. " \
214
+ "Known-safe values can be passed " \
215
+ "by wrapping them in Arel.sql()."
216
+ end
217
+
218
+ def timestamps_for_create
219
+ model.all_timestamp_attributes_in_model.index_with(connection.high_precision_current_timestamp)
220
+ end
221
+
134
222
  class Builder # :nodoc:
135
223
  attr_reader :model
136
224
 
137
- delegate :skip_duplicates?, :update_duplicates?, :keys, to: :insert_all
225
+ delegate :skip_duplicates?, :update_duplicates?, :keys, :keys_including_timestamps, :record_timestamps?, to: :insert_all
138
226
 
139
227
  def initialize(insert_all)
140
228
  @insert_all, @model, @connection = insert_all, insert_all.model, insert_all.connection
@@ -145,9 +233,10 @@ module ActiveRecord
145
233
  end
146
234
 
147
235
  def values_list
148
- types = extract_types_from_columns_on(model.table_name, keys: keys)
236
+ types = extract_types_from_columns_on(model.table_name, keys: keys_including_timestamps)
149
237
 
150
238
  values_list = insert_all.map_key_with_value do |key, value|
239
+ next value if Arel::Nodes::SqlLiteral === value
151
240
  connection.with_yaml_fallback(types[key].serialize(value))
152
241
  end
153
242
 
@@ -155,7 +244,19 @@ module ActiveRecord
155
244
  end
156
245
 
157
246
  def returning
158
- format_columns(insert_all.returning) if insert_all.returning
247
+ return unless insert_all.returning
248
+
249
+ if insert_all.returning.is_a?(String)
250
+ insert_all.returning
251
+ else
252
+ Array(insert_all.returning).map do |attribute|
253
+ if model.attribute_alias?(attribute)
254
+ "#{quote_column(model.attribute_alias(attribute))} AS #{quote_column(attribute)}"
255
+ else
256
+ quote_column(attribute)
257
+ end
258
+ end.join(",")
259
+ end
159
260
  end
160
261
 
161
262
  def conflict_target
@@ -173,22 +274,30 @@ module ActiveRecord
173
274
  end
174
275
 
175
276
  def touch_model_timestamps_unless(&block)
176
- model.send(:timestamp_attributes_for_update_in_model).map do |column_name|
277
+ return "" unless update_duplicates? && record_timestamps?
278
+
279
+ model.timestamp_attributes_for_update_in_model.filter_map do |column_name|
177
280
  if touch_timestamp_attribute?(column_name)
178
- "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END),"
281
+ "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE #{connection.high_precision_current_timestamp} END),"
179
282
  end
180
- end.compact.join
283
+ end.join
181
284
  end
182
285
 
286
+ def raw_update_sql
287
+ insert_all.update_sql
288
+ end
289
+
290
+ alias raw_update_sql? raw_update_sql
291
+
183
292
  private
184
293
  attr_reader :connection, :insert_all
185
294
 
186
295
  def touch_timestamp_attribute?(column_name)
187
- update_duplicates? && !insert_all.updatable_columns.include?(column_name)
296
+ insert_all.updatable_columns.exclude?(column_name)
188
297
  end
189
298
 
190
299
  def columns_list
191
- format_columns(insert_all.keys)
300
+ format_columns(insert_all.keys_including_timestamps)
192
301
  end
193
302
 
194
303
  def extract_types_from_columns_on(table_name, keys:)
@@ -205,7 +314,11 @@ module ActiveRecord
205
314
  end
206
315
 
207
316
  def quote_columns(columns)
208
- columns.map(&connection.method(:quote_column_name))
317
+ columns.map { |column| quote_column(column) }
318
+ end
319
+
320
+ def quote_column(column)
321
+ connection.quote_column_name(column)
209
322
  end
210
323
  end
211
324
  end
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  ##
11
11
  # :singleton-method:
12
12
  # Indicates the format used to generate the timestamp in the cache key, if
13
- # versioning is off. Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
13
+ # versioning is off. Accepts any of the symbols in +Time::DATE_FORMATS+.
14
14
  #
15
15
  # This is +:usec+, by default.
16
16
  class_attribute :cache_timestamp_format, instance_writer: false, default: :usec
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  # Indicates whether to use a stable #cache_key method that is accompanied
21
21
  # by a changing version in the #cache_version method.
22
22
  #
23
- # This is +true+, by default on Rails 5.2 and above.
23
+ # This is +true+, by default on \Rails 5.2 and above.
24
24
  class_attribute :cache_versioning, instance_writer: false, default: false
25
25
 
26
26
  ##
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  # Indicates whether to use a stable #cache_key method that is accompanied
29
29
  # by a changing version in the #cache_version method on collections.
30
30
  #
31
- # This is +false+, by default until Rails 6.1.
31
+ # This is +false+, by default until \Rails 6.1.
32
32
  class_attribute :collection_cache_versioning, instance_writer: false, default: false
33
33
  end
34
34
 
@@ -55,8 +55,8 @@ module ActiveRecord
55
55
  # user = User.find_by(name: 'Phusion')
56
56
  # user_path(user) # => "/users/Phusion"
57
57
  def to_param
58
- # We can't use alias_method here, because method 'id' optimizes itself on the fly.
59
- id && id.to_s # Be sure to stringify the id for routes
58
+ return unless id
59
+ Array(id).join(self.class.param_delimiter)
60
60
  end
61
61
 
62
62
  # Returns a stable cache key that can be used to identify this record.
@@ -64,7 +64,7 @@ module ActiveRecord
64
64
  # Product.new.cache_key # => "products/new"
65
65
  # Product.find(5).cache_key # => "products/5"
66
66
  #
67
- # If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
67
+ # If ActiveRecord::Base.cache_versioning is turned off, as it was in \Rails 5.1 and earlier,
68
68
  # the cache key will also include a version.
69
69
  #
70
70
  # Product.cache_versioning = false
@@ -79,7 +79,7 @@ module ActiveRecord
79
79
  timestamp = max_updated_column_timestamp
80
80
 
81
81
  if timestamp
82
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
82
+ timestamp = timestamp.utc.to_fs(cache_timestamp_format)
83
83
  "#{model_name.cache_key}/#{id}-#{timestamp}"
84
84
  else
85
85
  "#{model_name.cache_key}/#{id}"
@@ -101,11 +101,12 @@ module ActiveRecord
101
101
  timestamp = updated_at_before_type_cast
102
102
  if can_use_fast_cache_version?(timestamp)
103
103
  raw_timestamp_to_cache_version(timestamp)
104
+
104
105
  elsif timestamp = updated_at
105
- timestamp.utc.to_s(cache_timestamp_format)
106
+ timestamp.utc.to_fs(cache_timestamp_format)
106
107
  end
107
108
  elsif self.class.has_attribute?("updated_at")
108
- raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
109
+ raise ActiveModel::MissingAttributeError, "missing attribute 'updated_at' for #{self.class}"
109
110
  end
110
111
  end
111
112
 
@@ -177,7 +178,7 @@ module ActiveRecord
177
178
  def can_use_fast_cache_version?(timestamp)
178
179
  timestamp.is_a?(String) &&
179
180
  cache_timestamp_format == :usec &&
180
- default_timezone == :utc &&
181
+ self.class.connection.default_timezone == :utc &&
181
182
  !updated_at_came_from_user?
182
183
  end
183
184