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
@@ -5,55 +5,52 @@ require "concurrent/map"
5
5
  module ActiveRecord
6
6
  module Type
7
7
  class TypeMap # :nodoc:
8
- def initialize
8
+ def initialize(parent = nil)
9
9
  @mapping = {}
10
- @cache = Concurrent::Map.new do |h, key|
11
- h.fetch_or_store(key, Concurrent::Map.new)
12
- end
10
+ @parent = parent
11
+ @cache = Concurrent::Map.new
13
12
  end
14
13
 
15
- def lookup(lookup_key, *args)
16
- fetch(lookup_key, *args) { Type.default_value }
14
+ def lookup(lookup_key)
15
+ fetch(lookup_key) { Type.default_value }
17
16
  end
18
17
 
19
- def fetch(lookup_key, *args, &block)
20
- @cache[lookup_key].fetch_or_store(args) do
21
- perform_fetch(lookup_key, *args, &block)
18
+ def fetch(lookup_key, &block)
19
+ @cache.fetch_or_store(lookup_key) do
20
+ perform_fetch(lookup_key, &block)
22
21
  end
23
22
  end
24
23
 
25
24
  def register_type(key, value = nil, &block)
26
25
  raise ::ArgumentError unless value || block
27
- @cache.clear
28
26
 
29
27
  if block
30
28
  @mapping[key] = block
31
29
  else
32
30
  @mapping[key] = proc { value }
33
31
  end
32
+ @cache.clear
34
33
  end
35
34
 
36
35
  def alias_type(key, target_key)
37
- register_type(key) do |sql_type, *args|
36
+ register_type(key) do |sql_type|
38
37
  metadata = sql_type[/\(.*\)/, 0]
39
- lookup("#{target_key}#{metadata}", *args)
38
+ lookup("#{target_key}#{metadata}")
40
39
  end
41
40
  end
42
41
 
43
- def clear
44
- @mapping.clear
45
- end
46
-
47
- private
48
- def perform_fetch(lookup_key, *args)
42
+ protected
43
+ def perform_fetch(lookup_key, &block)
49
44
  matching_pair = @mapping.reverse_each.detect do |key, _|
50
45
  key === lookup_key
51
46
  end
52
47
 
53
48
  if matching_pair
54
- matching_pair.last.call(lookup_key, *args)
49
+ matching_pair.last.call(lookup_key)
50
+ elsif @parent
51
+ @parent.perform_fetch(lookup_key, &block)
55
52
  else
56
- yield lookup_key, *args
53
+ yield lookup_key
57
54
  end
58
55
  end
59
56
  end
@@ -47,8 +47,7 @@ module ActiveRecord
47
47
  end
48
48
 
49
49
  def adapter_name_from(model) # :nodoc:
50
- # TODO: this shouldn't depend on a connection to the database
51
- model.connection.adapter_name.downcase.to_sym
50
+ model.connection_db_config.adapter.to_sym
52
51
  end
53
52
 
54
53
  private
@@ -14,7 +14,7 @@ module ActiveRecord
14
14
  module ClassMethods
15
15
  # Validates that the specified attributes are not present (as defined by
16
16
  # Object#present?). If the attribute is an association, the associated object
17
- # is considered absent if it was marked for destruction.
17
+ # is also considered not present if it is marked for destruction.
18
18
  #
19
19
  # See ActiveModel::Validations::HelperMethods.validates_absence_of for more information.
20
20
  def validates_absence_of(*attr_names)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Validations
5
- class AssociatedValidator < ActiveModel::EachValidator #:nodoc:
5
+ class AssociatedValidator < ActiveModel::EachValidator # :nodoc:
6
6
  def validate_each(record, attribute, value)
7
7
  if Array(value).reject { |r| valid_object?(r) }.any?
8
8
  record.errors.add(attribute, :invalid, **options.merge(value: value))
@@ -42,14 +42,14 @@ module ActiveRecord
42
42
  # or an array of symbols. (e.g. <tt>on: :create</tt> or
43
43
  # <tt>on: :custom_validation_context</tt> or
44
44
  # <tt>on: [:create, :custom_validation_context]</tt>)
45
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
45
+ # * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
46
46
  # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
47
47
  # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
48
48
  # proc or string should return or evaluate to a +true+ or +false+ value.
49
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to
49
+ # * <tt>:unless</tt> - Specifies a method, proc, or string to call to
50
50
  # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
51
51
  # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
52
- # method, proc or string should return or evaluate to a +true+ or +false+
52
+ # method, proc, or string should return or evaluate to a +true+ or +false+
53
53
  # value.
54
54
  def validates_associated(*attr_names)
55
55
  validates_with AssociatedValidator, _merge_attributes(attr_names)
@@ -21,10 +21,11 @@ module ActiveRecord
21
21
 
22
22
  module ClassMethods
23
23
  # Validates whether the value of the specified attribute is numeric by
24
- # trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
25
- # is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt>
26
- # (if <tt>only_integer</tt> is set to +true+). Kernel.Float precision
27
- # defaults to the column's precision value or 15.
24
+ # trying to convert it to a float with +Kernel.Float+ (if
25
+ # <tt>only_integer</tt> is +false+) or applying it to the regular
26
+ # expression <tt>/\A[\+\-]?\d+\z/</tt> (if <tt>only_integer</tt> is set to
27
+ # +true+). +Kernel.Float+ precision defaults to the column's precision
28
+ # value or 15.
28
29
  #
29
30
  # See ActiveModel::Validations::HelperMethods.validates_numericality_of for more information.
30
31
  def validates_numericality_of(*attr_names)
@@ -13,9 +13,8 @@ module ActiveRecord
13
13
 
14
14
  module ClassMethods
15
15
  # Validates that the specified attributes are not blank (as defined by
16
- # Object#blank?), and, if the attribute is an association, that the
17
- # associated object is not marked for destruction. Happens by default
18
- # on save.
16
+ # Object#blank?). If the attribute is an association, the associated object
17
+ # is also considered blank if it is marked for destruction.
19
18
  #
20
19
  # class Person < ActiveRecord::Base
21
20
  # has_one :face
@@ -25,41 +24,19 @@ module ActiveRecord
25
24
  # The face attribute must be in the object and it cannot be blank or marked
26
25
  # for destruction.
27
26
  #
28
- # If you want to validate the presence of a boolean field (where the real values
29
- # are true and false), you will want to use
30
- # <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
31
- #
32
- # This is due to the way Object#blank? handles boolean values:
33
- # <tt>false.blank? # => true</tt>.
34
- #
35
27
  # This validator defers to the Active Model validation for presence, adding the
36
28
  # check to see that an associated object is not marked for destruction. This
37
29
  # prevents the parent object from validating successfully and saving, which then
38
30
  # deletes the associated object, thus putting the parent object into an invalid
39
31
  # state.
40
32
  #
33
+ # See ActiveModel::Validations::HelperMethods.validates_presence_of for
34
+ # more information.
35
+ #
41
36
  # NOTE: This validation will not fail while using it with an association
42
37
  # if the latter was assigned but not valid. If you want to ensure that
43
38
  # it is both present and valid, you also need to use
44
39
  # {validates_associated}[rdoc-ref:Validations::ClassMethods#validates_associated].
45
- #
46
- # Configuration options:
47
- # * <tt>:message</tt> - A custom error message (default is: "can't be blank").
48
- # * <tt>:on</tt> - Specifies the contexts where this validation is active.
49
- # Runs in all validation contexts by default +nil+. You can pass a symbol
50
- # or an array of symbols. (e.g. <tt>on: :create</tt> or
51
- # <tt>on: :custom_validation_context</tt> or
52
- # <tt>on: [:create, :custom_validation_context]</tt>)
53
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
54
- # the validation should occur (e.g. <tt>if: :allow_validation</tt>, or
55
- # <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
56
- # or string should return or evaluate to a +true+ or +false+ value.
57
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
58
- # if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
59
- # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
60
- # proc or string should return or evaluate to a +true+ or +false+ value.
61
- # * <tt>:strict</tt> - Specifies whether validation should be strict.
62
- # See ActiveModel::Validations#validates! for more information.
63
40
  def validates_presence_of(*attr_names)
64
41
  validates_with PresenceValidator, _merge_attributes(attr_names)
65
42
  end
@@ -20,10 +20,12 @@ module ActiveRecord
20
20
  finder_class = find_finder_class_for(record)
21
21
  value = map_enum_attribute(finder_class, attribute, value)
22
22
 
23
+ return if record.persisted? && !validation_needed?(finder_class, record, attribute)
24
+
23
25
  relation = build_relation(finder_class, attribute, value)
24
26
  if record.persisted?
25
27
  if finder_class.primary_key
26
- relation = relation.where.not(finder_class.primary_key => record.id_in_database)
28
+ relation = relation.where.not(finder_class.primary_key => [record.id_in_database])
27
29
  else
28
30
  raise UnknownPrimaryKey.new(finder_class, "Cannot validate uniqueness for persisted record without primary key.")
29
31
  end
@@ -64,6 +66,48 @@ module ActiveRecord
64
66
  class_hierarchy.detect { |klass| !klass.abstract_class? }
65
67
  end
66
68
 
69
+ def validation_needed?(klass, record, attribute)
70
+ return true if options[:conditions] || options.key?(:case_sensitive)
71
+
72
+ scope = Array(options[:scope])
73
+ attributes = scope + [attribute]
74
+ attributes = resolve_attributes(record, attributes)
75
+
76
+ return true if attributes.any? { |attr| record.attribute_changed?(attr) ||
77
+ record.read_attribute(attr).nil? }
78
+
79
+ !covered_by_unique_index?(klass, record, attribute, scope)
80
+ end
81
+
82
+ def covered_by_unique_index?(klass, record, attribute, scope)
83
+ @covered ||= self.attributes.map(&:to_s).select do |attr|
84
+ attributes = scope + [attr]
85
+ attributes = resolve_attributes(record, attributes)
86
+
87
+ klass.connection.schema_cache.indexes(klass.table_name).any? do |index|
88
+ index.unique &&
89
+ index.where.nil? &&
90
+ (Array(index.columns) - attributes).empty?
91
+ end
92
+ end
93
+
94
+ @covered.include?(attribute.to_s)
95
+ end
96
+
97
+ def resolve_attributes(record, attributes)
98
+ attributes.flat_map do |attribute|
99
+ reflection = record.class._reflect_on_association(attribute)
100
+
101
+ if reflection.nil?
102
+ attribute.to_s
103
+ elsif reflection.polymorphic?
104
+ [reflection.foreign_key, reflection.foreign_type]
105
+ else
106
+ reflection.foreign_key
107
+ end
108
+ end
109
+ end
110
+
67
111
  def build_relation(klass, attribute, value)
68
112
  relation = klass.unscoped
69
113
  comparison = relation.bind_attribute(attribute, value) do |attr, bind|
@@ -161,19 +205,19 @@ module ActiveRecord
161
205
  # <tt>WHERE</tt> SQL fragment to limit the uniqueness constraint lookup
162
206
  # (e.g. <tt>conditions: -> { where(status: 'active') }</tt>).
163
207
  # * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
164
- # non-text columns (+true+ by default).
208
+ # non-text columns. The default behavior respects the default database collation.
165
209
  # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
166
210
  # attribute is +nil+ (default is +false+).
167
211
  # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
168
212
  # attribute is blank (default is +false+).
169
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
213
+ # * <tt>:if</tt> - Specifies a method, proc, or string to call to determine
170
214
  # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
171
215
  # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
172
216
  # proc or string should return or evaluate to a +true+ or +false+ value.
173
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to
217
+ # * <tt>:unless</tt> - Specifies a method, proc, or string to call to
174
218
  # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
175
219
  # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
176
- # method, proc or string should return or evaluate to a +true+ or +false+
220
+ # method, proc, or string should return or evaluate to a +true+ or +false+
177
221
  # value.
178
222
  #
179
223
  # === Concurrency and integrity
@@ -221,7 +265,7 @@ module ActiveRecord
221
265
  # When the database catches such a duplicate insertion,
222
266
  # {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] will raise an ActiveRecord::StatementInvalid
223
267
  # exception. You can either choose to let this error propagate (which
224
- # will result in the default Rails exception page being shown), or you
268
+ # will result in the default \Rails exception page being shown), or you
225
269
  # can catch it and restart the transaction (e.g. by telling the user
226
270
  # that the title already exists, and asking them to re-enter the title).
227
271
  # This technique is also known as
@@ -236,6 +280,7 @@ module ActiveRecord
236
280
  # The following bundled adapters throw the ActiveRecord::RecordNotUnique exception:
237
281
  #
238
282
  # * ActiveRecord::ConnectionAdapters::Mysql2Adapter.
283
+ # * ActiveRecord::ConnectionAdapters::TrilogyAdapter.
239
284
  # * ActiveRecord::ConnectionAdapters::SQLite3Adapter.
240
285
  # * ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.
241
286
  def validates_uniqueness_of(*attr_names)
@@ -30,10 +30,12 @@ module ActiveRecord
30
30
 
31
31
  # = Active Record \Validations
32
32
  #
33
- # Active Record includes the majority of its validations from ActiveModel::Validations
34
- # all of which accept the <tt>:on</tt> argument to define the context where the
35
- # validations are active. Active Record will always supply either the context of
36
- # <tt>:create</tt> or <tt>:update</tt> dependent on whether the model is a
33
+ # Active Record includes the majority of its validations from ActiveModel::Validations.
34
+ #
35
+ # In Active Record, all validations are performed on save by default.
36
+ # Validations accept the <tt>:on</tt> argument to define the context where
37
+ # the validations are active. Active Record will pass either the context of
38
+ # <tt>:create</tt> or <tt>:update</tt> depending on whether the model is a
37
39
  # {new_record?}[rdoc-ref:Persistence#new_record?].
38
40
  module Validations
39
41
  extend ActiveSupport::Concern
@@ -60,6 +62,8 @@ module ActiveRecord
60
62
  #
61
63
  # If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
62
64
  # {new_record?}[rdoc-ref:Persistence#new_record?] is +true+, and to <tt>:update</tt> if it is not.
65
+ # If the argument is an array of contexts, <tt>post.valid?([:create, :update])</tt>, the validations are
66
+ # run within multiple contexts.
63
67
  #
64
68
  # \Validations with no <tt>:on</tt> option will run no matter the context. \Validations with
65
69
  # some <tt>:on</tt> option will only run in the specified context.
@@ -3,7 +3,7 @@
3
3
  require_relative "gem_version"
4
4
 
5
5
  module ActiveRecord
6
- # Returns the version of the currently loaded ActiveRecord as a <tt>Gem::Version</tt>
6
+ # Returns the currently loaded version of Active Record as a +Gem::Version+.
7
7
  def self.version
8
8
  gem_version
9
9
  end