activerecord 7.0.8.7 → 7.1.0.beta1

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 (227) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1339 -1572
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +15 -16
  5. data/lib/active_record/aggregations.rb +16 -13
  6. data/lib/active_record/association_relation.rb +1 -1
  7. data/lib/active_record/associations/association.rb +18 -3
  8. data/lib/active_record/associations/association_scope.rb +16 -9
  9. data/lib/active_record/associations/belongs_to_association.rb +14 -6
  10. data/lib/active_record/associations/builder/association.rb +3 -3
  11. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  13. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  14. data/lib/active_record/associations/collection_association.rb +17 -9
  15. data/lib/active_record/associations/collection_proxy.rb +16 -11
  16. data/lib/active_record/associations/foreign_association.rb +10 -3
  17. data/lib/active_record/associations/has_many_association.rb +20 -13
  18. data/lib/active_record/associations/has_many_through_association.rb +10 -6
  19. data/lib/active_record/associations/has_one_association.rb +10 -3
  20. data/lib/active_record/associations/join_dependency.rb +10 -8
  21. data/lib/active_record/associations/preloader/association.rb +27 -6
  22. data/lib/active_record/associations/preloader.rb +12 -9
  23. data/lib/active_record/associations/singular_association.rb +1 -1
  24. data/lib/active_record/associations/through_association.rb +22 -11
  25. data/lib/active_record/associations.rb +193 -97
  26. data/lib/active_record/attribute_assignment.rb +0 -2
  27. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  28. data/lib/active_record/attribute_methods/dirty.rb +40 -26
  29. data/lib/active_record/attribute_methods/primary_key.rb +76 -24
  30. data/lib/active_record/attribute_methods/query.rb +28 -16
  31. data/lib/active_record/attribute_methods/read.rb +18 -5
  32. data/lib/active_record/attribute_methods/serialization.rb +150 -31
  33. data/lib/active_record/attribute_methods/write.rb +3 -3
  34. data/lib/active_record/attribute_methods.rb +105 -21
  35. data/lib/active_record/attributes.rb +3 -3
  36. data/lib/active_record/autosave_association.rb +55 -9
  37. data/lib/active_record/base.rb +7 -2
  38. data/lib/active_record/callbacks.rb +10 -24
  39. data/lib/active_record/coders/column_serializer.rb +61 -0
  40. data/lib/active_record/coders/json.rb +1 -1
  41. data/lib/active_record/coders/yaml_column.rb +70 -42
  42. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
  43. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  44. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
  45. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
  46. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  47. data/lib/active_record/connection_adapters/abstract/database_statements.rb +109 -32
  48. data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
  49. data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
  50. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  51. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  52. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
  53. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -122
  54. data/lib/active_record/connection_adapters/abstract/transaction.rb +280 -58
  55. data/lib/active_record/connection_adapters/abstract_adapter.rb +502 -91
  56. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +200 -108
  57. data/lib/active_record/connection_adapters/column.rb +9 -0
  58. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  59. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
  60. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
  61. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  62. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
  63. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -12
  65. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
  66. data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
  67. data/lib/active_record/connection_adapters/pool_config.rb +14 -5
  68. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  69. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
  70. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +76 -29
  71. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  72. data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -6
  73. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  74. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  75. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
  76. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +42 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +351 -54
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +336 -168
  79. data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
  80. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  81. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +42 -36
  82. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
  83. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
  84. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
  85. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +162 -77
  86. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  87. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
  88. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  89. data/lib/active_record/connection_adapters.rb +3 -1
  90. data/lib/active_record/connection_handling.rb +71 -94
  91. data/lib/active_record/core.rb +128 -138
  92. data/lib/active_record/counter_cache.rb +46 -25
  93. data/lib/active_record/database_configurations/database_config.rb +9 -3
  94. data/lib/active_record/database_configurations/hash_config.rb +22 -12
  95. data/lib/active_record/database_configurations/url_config.rb +17 -11
  96. data/lib/active_record/database_configurations.rb +86 -33
  97. data/lib/active_record/delegated_type.rb +8 -3
  98. data/lib/active_record/deprecator.rb +7 -0
  99. data/lib/active_record/destroy_association_async_job.rb +2 -0
  100. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  101. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  102. data/lib/active_record/encryption/config.rb +25 -1
  103. data/lib/active_record/encryption/configurable.rb +12 -19
  104. data/lib/active_record/encryption/context.rb +10 -3
  105. data/lib/active_record/encryption/contexts.rb +5 -1
  106. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  107. data/lib/active_record/encryption/encryptable_record.rb +36 -18
  108. data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
  109. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
  110. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +2 -2
  111. data/lib/active_record/encryption/key_generator.rb +12 -1
  112. data/lib/active_record/encryption/message_serializer.rb +2 -0
  113. data/lib/active_record/encryption/properties.rb +3 -3
  114. data/lib/active_record/encryption/scheme.rb +19 -22
  115. data/lib/active_record/encryption.rb +1 -0
  116. data/lib/active_record/enum.rb +113 -26
  117. data/lib/active_record/errors.rb +89 -15
  118. data/lib/active_record/explain.rb +23 -3
  119. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  120. data/lib/active_record/fixture_set/render_context.rb +2 -0
  121. data/lib/active_record/fixture_set/table_row.rb +29 -8
  122. data/lib/active_record/fixtures.rb +119 -71
  123. data/lib/active_record/future_result.rb +30 -5
  124. data/lib/active_record/gem_version.rb +4 -4
  125. data/lib/active_record/inheritance.rb +30 -16
  126. data/lib/active_record/insert_all.rb +55 -8
  127. data/lib/active_record/integration.rb +8 -8
  128. data/lib/active_record/internal_metadata.rb +118 -30
  129. data/lib/active_record/locking/pessimistic.rb +5 -2
  130. data/lib/active_record/log_subscriber.rb +29 -12
  131. data/lib/active_record/marshalling.rb +56 -0
  132. data/lib/active_record/message_pack.rb +124 -0
  133. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  134. data/lib/active_record/middleware/database_selector.rb +5 -7
  135. data/lib/active_record/middleware/shard_selector.rb +3 -1
  136. data/lib/active_record/migration/command_recorder.rb +100 -4
  137. data/lib/active_record/migration/compatibility.rb +131 -5
  138. data/lib/active_record/migration/default_strategy.rb +23 -0
  139. data/lib/active_record/migration/execution_strategy.rb +19 -0
  140. data/lib/active_record/migration.rb +213 -109
  141. data/lib/active_record/model_schema.rb +47 -27
  142. data/lib/active_record/nested_attributes.rb +28 -3
  143. data/lib/active_record/normalization.rb +158 -0
  144. data/lib/active_record/persistence.rb +183 -33
  145. data/lib/active_record/promise.rb +84 -0
  146. data/lib/active_record/query_cache.rb +3 -21
  147. data/lib/active_record/query_logs.rb +77 -52
  148. data/lib/active_record/query_logs_formatter.rb +41 -0
  149. data/lib/active_record/querying.rb +15 -2
  150. data/lib/active_record/railtie.rb +107 -45
  151. data/lib/active_record/railties/controller_runtime.rb +10 -5
  152. data/lib/active_record/railties/databases.rake +139 -145
  153. data/lib/active_record/railties/job_runtime.rb +23 -0
  154. data/lib/active_record/readonly_attributes.rb +32 -5
  155. data/lib/active_record/reflection.rb +169 -45
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
  157. data/lib/active_record/relation/batches.rb +190 -61
  158. data/lib/active_record/relation/calculations.rb +152 -63
  159. data/lib/active_record/relation/delegation.rb +22 -8
  160. data/lib/active_record/relation/finder_methods.rb +85 -15
  161. data/lib/active_record/relation/merger.rb +2 -0
  162. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
  163. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  164. data/lib/active_record/relation/predicate_builder.rb +26 -14
  165. data/lib/active_record/relation/query_attribute.rb +2 -1
  166. data/lib/active_record/relation/query_methods.rb +351 -62
  167. data/lib/active_record/relation/spawn_methods.rb +18 -1
  168. data/lib/active_record/relation.rb +76 -35
  169. data/lib/active_record/result.rb +19 -5
  170. data/lib/active_record/runtime_registry.rb +10 -1
  171. data/lib/active_record/sanitization.rb +51 -11
  172. data/lib/active_record/schema.rb +2 -3
  173. data/lib/active_record/schema_dumper.rb +41 -7
  174. data/lib/active_record/schema_migration.rb +68 -33
  175. data/lib/active_record/scoping/default.rb +15 -5
  176. data/lib/active_record/scoping/named.rb +2 -2
  177. data/lib/active_record/scoping.rb +2 -1
  178. data/lib/active_record/secure_password.rb +60 -0
  179. data/lib/active_record/secure_token.rb +21 -3
  180. data/lib/active_record/signed_id.rb +7 -5
  181. data/lib/active_record/store.rb +8 -8
  182. data/lib/active_record/suppressor.rb +3 -1
  183. data/lib/active_record/table_metadata.rb +10 -1
  184. data/lib/active_record/tasks/database_tasks.rb +127 -105
  185. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  186. data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
  187. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -7
  188. data/lib/active_record/test_fixtures.rb +113 -96
  189. data/lib/active_record/timestamp.rb +26 -14
  190. data/lib/active_record/token_for.rb +113 -0
  191. data/lib/active_record/touch_later.rb +11 -6
  192. data/lib/active_record/transactions.rb +36 -10
  193. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  194. data/lib/active_record/type/internal/timezone.rb +7 -2
  195. data/lib/active_record/type/time.rb +4 -0
  196. data/lib/active_record/validations/absence.rb +1 -1
  197. data/lib/active_record/validations/numericality.rb +5 -4
  198. data/lib/active_record/validations/presence.rb +5 -28
  199. data/lib/active_record/validations/uniqueness.rb +47 -2
  200. data/lib/active_record/validations.rb +8 -4
  201. data/lib/active_record/version.rb +1 -1
  202. data/lib/active_record.rb +121 -16
  203. data/lib/arel/errors.rb +10 -0
  204. data/lib/arel/factory_methods.rb +4 -0
  205. data/lib/arel/nodes/binary.rb +6 -1
  206. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  207. data/lib/arel/nodes/cte.rb +36 -0
  208. data/lib/arel/nodes/fragments.rb +35 -0
  209. data/lib/arel/nodes/homogeneous_in.rb +0 -8
  210. data/lib/arel/nodes/leading_join.rb +8 -0
  211. data/lib/arel/nodes/node.rb +111 -2
  212. data/lib/arel/nodes/sql_literal.rb +6 -0
  213. data/lib/arel/nodes/table_alias.rb +4 -0
  214. data/lib/arel/nodes.rb +4 -0
  215. data/lib/arel/predications.rb +2 -0
  216. data/lib/arel/table.rb +9 -5
  217. data/lib/arel/visitors/mysql.rb +8 -1
  218. data/lib/arel/visitors/to_sql.rb +81 -17
  219. data/lib/arel/visitors/visitor.rb +2 -2
  220. data/lib/arel.rb +16 -2
  221. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  222. data/lib/rails/generators/active_record/migration.rb +3 -1
  223. data/lib/rails/generators/active_record/model/USAGE +113 -0
  224. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  225. metadata +52 -17
  226. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  227. data/lib/active_record/null_relation.rb +0 -63
@@ -4,12 +4,17 @@ module ActiveRecord
4
4
  module Type
5
5
  module Internal
6
6
  module Timezone
7
+ def initialize(timezone: nil, **kwargs)
8
+ super(**kwargs)
9
+ @timezone = timezone
10
+ end
11
+
7
12
  def is_utc?
8
- ActiveRecord.default_timezone == :utc
13
+ default_timezone == :utc
9
14
  end
10
15
 
11
16
  def default_timezone
12
- ActiveRecord.default_timezone
17
+ @timezone || ActiveRecord.default_timezone
13
18
  end
14
19
  end
15
20
  end
@@ -17,6 +17,10 @@ module ActiveRecord
17
17
  end
18
18
  end
19
19
 
20
+ def serialize_cast_value(value) # :nodoc:
21
+ Value.new(super) if value
22
+ end
23
+
20
24
  private
21
25
  def cast_value(value)
22
26
  case value = super
@@ -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)
@@ -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
+ (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|
@@ -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 currently loaded version of Active Record 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
data/lib/active_record.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2004-2022 David Heinemeier Hansson
4
+ # Copyright (c) David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -30,9 +30,11 @@ require "arel"
30
30
  require "yaml"
31
31
 
32
32
  require "active_record/version"
33
+ require "active_record/deprecator"
33
34
  require "active_model/attribute_set"
34
35
  require "active_record/errors"
35
36
 
37
+ # :include: activerecord/README.rdoc
36
38
  module ActiveRecord
37
39
  extend ActiveSupport::Autoload
38
40
 
@@ -47,18 +49,22 @@ module ActiveRecord
47
49
  autoload :Encryption
48
50
  autoload :Enum
49
51
  autoload :Explain
52
+ autoload :FixtureSet, "active_record/fixtures"
50
53
  autoload :Inheritance
51
54
  autoload :Integration
52
55
  autoload :InternalMetadata
56
+ autoload :LogSubscriber
57
+ autoload :Marshalling
53
58
  autoload :Migration
54
59
  autoload :Migrator, "active_record/migration"
55
60
  autoload :ModelSchema
56
61
  autoload :NestedAttributes
57
62
  autoload :NoTouching
63
+ autoload :Normalization
58
64
  autoload :Persistence
59
65
  autoload :QueryCache
60
- autoload :Querying
61
66
  autoload :QueryLogs
67
+ autoload :Querying
62
68
  autoload :ReadonlyAttributes
63
69
  autoload :RecordInvalid, "active_record/validations"
64
70
  autoload :Reflection
@@ -68,6 +74,7 @@ module ActiveRecord
68
74
  autoload :SchemaDumper
69
75
  autoload :SchemaMigration
70
76
  autoload :Scoping
77
+ autoload :SecurePassword
71
78
  autoload :SecureToken
72
79
  autoload :Serialization
73
80
  autoload :SignedId
@@ -76,6 +83,7 @@ module ActiveRecord
76
83
  autoload :TestDatabases
77
84
  autoload :TestFixtures, "active_record/fixtures"
78
85
  autoload :Timestamp
86
+ autoload :TokenFor
79
87
  autoload :TouchLater
80
88
  autoload :Transactions
81
89
  autoload :Translation
@@ -93,7 +101,7 @@ module ActiveRecord
93
101
  autoload :DisableJoinsAssociationRelation
94
102
  autoload :FutureResult
95
103
  autoload :LegacyYamlAdapter
96
- autoload :NullRelation
104
+ autoload :Promise
97
105
  autoload :Relation
98
106
  autoload :Result
99
107
  autoload :StatementCache
@@ -101,17 +109,18 @@ module ActiveRecord
101
109
  autoload :Type
102
110
 
103
111
  autoload_under "relation" do
104
- autoload :QueryMethods
105
- autoload :FinderMethods
112
+ autoload :Batches
106
113
  autoload :Calculations
114
+ autoload :Delegation
115
+ autoload :FinderMethods
107
116
  autoload :PredicateBuilder
117
+ autoload :QueryMethods
108
118
  autoload :SpawnMethods
109
- autoload :Batches
110
- autoload :Delegation
111
119
  end
112
120
  end
113
121
 
114
122
  module Coders
123
+ autoload :ColumnSerializer, "active_record/coders/column_serializer"
115
124
  autoload :JSON, "active_record/coders/json"
116
125
  autoload :YAMLColumn, "active_record/coders/yaml_column"
117
126
  end
@@ -165,6 +174,9 @@ module ActiveRecord
165
174
  autoload :SQLiteDatabaseTasks, "active_record/tasks/sqlite_database_tasks"
166
175
  end
167
176
 
177
+ singleton_class.attr_accessor :disable_prepared_statements
178
+ self.disable_prepared_statements = false
179
+
168
180
  # Lazily load the schema cache. This option will load the schema cache
169
181
  # when a connection is established rather than on boot. If set,
170
182
  # +config.active_record.use_schema_cache_dump+ will be set to false.
@@ -177,9 +189,6 @@ module ActiveRecord
177
189
  singleton_class.attr_accessor :schema_cache_ignored_tables
178
190
  self.schema_cache_ignored_tables = []
179
191
 
180
- singleton_class.attr_accessor :legacy_connection_handling
181
- self.legacy_connection_handling = true
182
-
183
192
  singleton_class.attr_reader :default_timezone
184
193
 
185
194
  # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
@@ -194,12 +203,53 @@ module ActiveRecord
194
203
 
195
204
  self.default_timezone = :utc
196
205
 
206
+ # The action to take when database query produces warning.
207
+ # Must be one of :ignore, :log, :raise, :report, or a custom proc.
208
+ # The default is :ignore.
209
+ singleton_class.attr_reader :db_warnings_action
210
+
211
+ def self.db_warnings_action=(action)
212
+ @db_warnings_action =
213
+ case action
214
+ when :ignore
215
+ nil
216
+ when :log
217
+ ->(warning) do
218
+ warning_message = "[#{warning.class}] #{warning.message}"
219
+ warning_message += " (#{warning.code})" if warning.code
220
+ ActiveRecord::Base.logger.warn(warning_message)
221
+ end
222
+ when :raise
223
+ ->(warning) { raise warning }
224
+ when :report
225
+ ->(warning) { Rails.error.report(warning, handled: true) }
226
+ when Proc
227
+ action
228
+ else
229
+ raise ArgumentError, "db_warnings_action must be one of :ignore, :log, :raise, :report, or a custom proc."
230
+ end
231
+ end
232
+
233
+ self.db_warnings_action = :ignore
234
+
235
+ # Specify allowlist of database warnings.
236
+ singleton_class.attr_accessor :db_warnings_ignore
237
+ self.db_warnings_ignore = []
238
+
197
239
  singleton_class.attr_accessor :writing_role
198
240
  self.writing_role = :writing
199
241
 
200
242
  singleton_class.attr_accessor :reading_role
201
243
  self.reading_role = :reading
202
244
 
245
+ def self.legacy_connection_handling=(_)
246
+ raise ArgumentError, <<~MSG.squish
247
+ The `legacy_connection_handling` setter was deprecated in 7.0 and removed in 7.1,
248
+ but is still defined in your configuration. Please remove this call as it no longer
249
+ has any effect."
250
+ MSG
251
+ end
252
+
203
253
  # Sets the async_query_executor for an application. By default the thread pool executor
204
254
  # set to +nil+ which will not run queries in the background. Applications must configure
205
255
  # a thread pool executor to use this feature. Options are:
@@ -258,6 +308,21 @@ module ActiveRecord
258
308
  singleton_class.attr_accessor :maintain_test_schema
259
309
  self.maintain_test_schema = nil
260
310
 
311
+ singleton_class.attr_accessor :raise_on_assign_to_attr_readonly
312
+ self.raise_on_assign_to_attr_readonly = false
313
+
314
+ singleton_class.attr_accessor :belongs_to_required_validates_foreign_key
315
+ self.belongs_to_required_validates_foreign_key = true
316
+
317
+ singleton_class.attr_accessor :before_committed_on_all_records
318
+ self.before_committed_on_all_records = false
319
+
320
+ singleton_class.attr_accessor :run_after_transaction_callbacks_in_order_defined
321
+ self.run_after_transaction_callbacks_in_order_defined = false
322
+
323
+ singleton_class.attr_accessor :commit_transaction_on_non_local_return
324
+ self.commit_transaction_on_non_local_return = false
325
+
261
326
  ##
262
327
  # :singleton-method:
263
328
  # Specify a threshold for the size of query result sets. If the number of
@@ -302,6 +367,12 @@ module ActiveRecord
302
367
  singleton_class.attr_accessor :timestamped_migrations
303
368
  self.timestamped_migrations = true
304
369
 
370
+ ##
371
+ # :singleton-method:
372
+ # Specify strategy to use for executing migrations.
373
+ singleton_class.attr_accessor :migration_strategy
374
+ self.migration_strategy = Migration::DefaultStrategy
375
+
305
376
  ##
306
377
  # :singleton-method:
307
378
  # Specify whether schema dump should happen at the end of the
@@ -321,12 +392,19 @@ module ActiveRecord
321
392
  singleton_class.attr_accessor :dump_schemas
322
393
  self.dump_schemas = :schema_search_path
323
394
 
324
- ##
325
- # :singleton-method:
326
- # Show a warning when Rails couldn't parse your database.yml
327
- # for multiple databases.
328
- singleton_class.attr_accessor :suppress_multiple_database_warning
329
- self.suppress_multiple_database_warning = false
395
+ def self.suppress_multiple_database_warning
396
+ ActiveRecord.deprecator.warn(<<-MSG.squish)
397
+ config.active_record.suppress_multiple_database_warning is deprecated and will be removed in Rails 7.2.
398
+ It no longer has any effect and should be removed from the configuration file.
399
+ MSG
400
+ end
401
+
402
+ def self.suppress_multiple_database_warning=(value)
403
+ ActiveRecord.deprecator.warn(<<-MSG.squish)
404
+ config.active_record.suppress_multiple_database_warning= is deprecated and will be removed in Rails 7.2.
405
+ It no longer has any effect and should be removed from the configuration file.
406
+ MSG
407
+ end
330
408
 
331
409
  ##
332
410
  # :singleton-method:
@@ -337,6 +415,13 @@ module ActiveRecord
337
415
  singleton_class.attr_accessor :verify_foreign_keys_for_fixtures
338
416
  self.verify_foreign_keys_for_fixtures = false
339
417
 
418
+ ##
419
+ # :singleton-method:
420
+ # If true, Rails will continue allowing plural association names in where clauses on singular associations
421
+ # This behavior will be removed in Rails 7.2.
422
+ singleton_class.attr_accessor :allow_deprecated_singular_associations_name
423
+ self.allow_deprecated_singular_associations_name = true
424
+
340
425
  singleton_class.attr_accessor :query_transformers
341
426
  self.query_transformers = []
342
427
 
@@ -362,6 +447,21 @@ module ActiveRecord
362
447
  singleton_class.attr_accessor :yaml_column_permitted_classes
363
448
  self.yaml_column_permitted_classes = [Symbol]
364
449
 
450
+ ##
451
+ # :singleton-method:
452
+ # Controls when to generate a value for <tt>has_secure_token</tt>
453
+ # declarations. Defaults to <tt>:create</tt>.
454
+ singleton_class.attr_accessor :generate_secure_token_on
455
+ self.generate_secure_token_on = :create
456
+
457
+ def self.marshalling_format_version
458
+ Marshalling.format_version
459
+ end
460
+
461
+ def self.marshalling_format_version=(value)
462
+ Marshalling.format_version = value
463
+ end
464
+
365
465
  def self.eager_load!
366
466
  super
367
467
  ActiveRecord::Locking.eager_load!
@@ -371,6 +471,11 @@ module ActiveRecord
371
471
  ActiveRecord::ConnectionAdapters.eager_load!
372
472
  ActiveRecord::Encryption.eager_load!
373
473
  end
474
+
475
+ # Explicitly closes all database connections in all pools.
476
+ def self.disconnect_all!
477
+ ConnectionAdapters::PoolConfig.disconnect_all!
478
+ end
374
479
  end
375
480
 
376
481
  ActiveSupport.on_load(:active_record) do
data/lib/arel/errors.rb CHANGED
@@ -6,4 +6,14 @@ module Arel # :nodoc: all
6
6
 
7
7
  class EmptyJoinError < ArelError
8
8
  end
9
+
10
+ class BindError < ArelError
11
+ def initialize(message, sql = nil)
12
+ if sql
13
+ super("#{message} in: #{sql.inspect}")
14
+ else
15
+ super(message)
16
+ end
17
+ end
18
+ end
9
19
  end
@@ -45,5 +45,9 @@ module Arel # :nodoc: all
45
45
  def coalesce(*exprs)
46
46
  Nodes::NamedFunction.new "COALESCE", exprs
47
47
  end
48
+
49
+ def cast(name, type)
50
+ Nodes::NamedFunction.new "CAST", [name.as(type)]
51
+ end
48
52
  end
49
53
  end
@@ -39,6 +39,12 @@ module Arel # :nodoc: all
39
39
  end
40
40
  end
41
41
 
42
+ class As < Binary
43
+ def to_cte
44
+ Arel::Nodes::Cte.new(left.name, right)
45
+ end
46
+ end
47
+
42
48
  class Between < Binary; include FetchAttribute; end
43
49
 
44
50
  class GreaterThan < Binary
@@ -112,7 +118,6 @@ module Arel # :nodoc: all
112
118
  end
113
119
 
114
120
  %w{
115
- As
116
121
  Assignment
117
122
  Join
118
123
  Union
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Nodes
5
+ class BoundSqlLiteral < NodeExpression
6
+ attr_reader :sql_with_placeholders, :positional_binds, :named_binds
7
+
8
+ def initialize(sql_with_placeholders, positional_binds, named_binds)
9
+ if !positional_binds.empty? && !named_binds.empty?
10
+ raise BindError.new("cannot mix positional and named binds", sql_with_placeholders)
11
+ elsif !positional_binds.empty?
12
+ if positional_binds.size != (expected = sql_with_placeholders.count("?"))
13
+ raise BindError.new("wrong number of bind variables (#{positional_binds.size} for #{expected})", sql_with_placeholders)
14
+ end
15
+ elsif !named_binds.empty?
16
+ tokens_in_string = sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)/).flatten.map(&:to_sym).uniq
17
+ tokens_in_hash = named_binds.keys.map(&:to_sym).uniq
18
+
19
+ if !(missing = (tokens_in_string - tokens_in_hash)).empty?
20
+ if missing.size == 1
21
+ raise BindError.new("missing value for #{missing.first.inspect}", sql_with_placeholders)
22
+ else
23
+ raise BindError.new("missing values for #{missing.inspect}", sql_with_placeholders)
24
+ end
25
+ end
26
+ end
27
+
28
+ @sql_with_placeholders = sql_with_placeholders
29
+ if !positional_binds.empty?
30
+ @positional_binds = positional_binds
31
+ @named_binds = nil
32
+ else
33
+ @positional_binds = nil
34
+ @named_binds = named_binds
35
+ end
36
+ end
37
+
38
+ def hash
39
+ [self.class, sql_with_placeholders, positional_binds, named_binds].hash
40
+ end
41
+
42
+ def eql?(other)
43
+ self.class == other.class &&
44
+ sql_with_placeholders == other.sql_with_placeholders &&
45
+ positional_binds == other.positional_binds &&
46
+ named_binds == other.named_binds
47
+ end
48
+ alias :== :eql?
49
+
50
+ def +(other)
51
+ raise ArgumentError, "Expected Arel node" unless Arel.arel_node?(other)
52
+
53
+ Fragments.new([self, other])
54
+ end
55
+
56
+ def inspect
57
+ "#<#{self.class.name} #{sql_with_placeholders.inspect} #{(named_binds || positional_binds).inspect}>"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Nodes
5
+ class Cte < Arel::Nodes::Binary
6
+ alias :name :left
7
+ alias :relation :right
8
+ attr_reader :materialized
9
+
10
+ def initialize(name, relation, materialized: nil)
11
+ super(name, relation)
12
+ @materialized = materialized
13
+ end
14
+
15
+ def hash
16
+ [name, relation, materialized].hash
17
+ end
18
+
19
+ def eql?(other)
20
+ self.class == other.class &&
21
+ self.name == other.name &&
22
+ self.relation == other.relation &&
23
+ self.materialized == other.materialized
24
+ end
25
+ alias :== :eql?
26
+
27
+ def to_cte
28
+ self
29
+ end
30
+
31
+ def to_table
32
+ Arel::Table.new(name)
33
+ end
34
+ end
35
+ end
36
+ end