diff --git a/gems/activemodel/6.0/_test/test.rb b/gems/activemodel/6.0/_test/test.rb
index 7d0c7864..a3d3b406 100644
--- a/gems/activemodel/6.0/_test/test.rb
+++ b/gems/activemodel/6.0/_test/test.rb
@@ -5,8 +5,17 @@ class Person
validates :name, presence: true, length: { maximum: 100 }
validates :email, presence: true, if: [:foo?, -> { age >= 20 }]
+ validate :should_be_satisfied_special_email_rule
def foo? = true
+
+ def should_be_satisfied_special_email_rule
+ if Time.current >= Time.zone.local(2024, 10)
+ errors.add(:email, -> (_person, _options) { "must be satisfied at least 3 rules after #{Time.zone.local(2024, 10)}" }) if [/a-z/, /A-Z/, /0-9/, /[+]/].count {|rule| email.match?(rule) } > 3
+ else
+ errors.add(:email, 'must be satisfied at least 2 rules') if [/a-z/, /A-Z/, /0-9/].count {|rule| email.match?(rule) } > 2
+ end
+ end
end
person = Person.new(name: 'John Doe')
diff --git a/gems/activemodel/6.0/_test/test.rbs b/gems/activemodel/6.0/_test/test.rbs
index b3c14da2..7387aced 100644
--- a/gems/activemodel/6.0/_test/test.rbs
+++ b/gems/activemodel/6.0/_test/test.rbs
@@ -8,4 +8,5 @@ class Person
attr_accessor email: String
def foo?: () -> bool
+ def should_be_satisfied_special_email_rule: () -> void
end
diff --git a/gems/activemodel/6.0/activemodel-generated.rbs b/gems/activemodel/6.0/activemodel-generated.rbs
index a751383e..8b8c11ed 100644
--- a/gems/activemodel/6.0/activemodel-generated.rbs
+++ b/gems/activemodel/6.0/activemodel-generated.rbs
@@ -1500,49 +1500,6 @@ module ActiveModel
# person.errors.to_hash(true) # => {:name=>["name cannot be nil"]}
def to_hash: (?bool full_messages) -> untyped
- # Adds +message+ to the error messages and used validator type to +details+ on +attribute+.
- # More than one error can be added to the same +attribute+.
- # If no +message+ is supplied, :invalid is assumed.
- #
- # person.errors.add(:name)
- # # => ["is invalid"]
- # person.errors.add(:name, :not_implemented, message: "must be implemented")
- # # => ["is invalid", "must be implemented"]
- #
- # person.errors.messages
- # # => {:name=>["is invalid", "must be implemented"]}
- #
- # person.errors.details
- # # => {:name=>[{error: :not_implemented}, {error: :invalid}]}
- #
- # If +message+ is a symbol, it will be translated using the appropriate
- # scope (see +generate_message+).
- #
- # If +message+ is a proc, it will be called, allowing for things like
- # Time.now to be used within an error.
- #
- # If the :strict option is set to +true+, it will raise
- # ActiveModel::StrictValidationFailed instead of adding the error.
- # :strict option can also be set to any other exception.
- #
- # person.errors.add(:name, :invalid, strict: true)
- # # => ActiveModel::StrictValidationFailed: Name is invalid
- # person.errors.add(:name, :invalid, strict: NameIsInvalid)
- # # => NameIsInvalid: Name is invalid
- #
- # person.errors.messages # => {}
- #
- # +attribute+ should be set to :base if the error is not
- # directly associated with a single attribute.
- #
- # person.errors.add(:base, :name_or_email_blank,
- # message: "either name or email must be present")
- # person.errors.messages
- # # => {:base=>["either name or email must be present"]}
- # person.errors.details
- # # => {:base=>[{error: :name_or_email_blank}]}
- def add: (untyped attribute, ?::Symbol message, ?::Hash[untyped, untyped] options) -> untyped
-
# Returns +true+ if an error on the attribute with the given message is
# present, or +false+ otherwise. +message+ is treated the same as for +add+.
#
diff --git a/gems/activemodel/6.0/activemodel.rbs b/gems/activemodel/6.0/activemodel.rbs
index 92e5f202..66e048d8 100644
--- a/gems/activemodel/6.0/activemodel.rbs
+++ b/gems/activemodel/6.0/activemodel.rbs
@@ -251,7 +251,7 @@ module ActiveModel
# person = Person.new
# person.valid? # => false
# person.errors # => #
- def errors: () -> untyped
+ def errors: () -> Errors
# Runs all the specified validations and returns +true+ if no errors were
# added otherwise +false+.
@@ -498,3 +498,50 @@ module ActiveModel
end
end
end
+
+module ActiveModel
+ class Errors
+ # Adds +message+ to the error messages and used validator type to +details+ on +attribute+.
+ # More than one error can be added to the same +attribute+.
+ # If no +message+ is supplied, :invalid is assumed.
+ #
+ # person.errors.add(:name)
+ # # => ["is invalid"]
+ # person.errors.add(:name, :not_implemented, message: "must be implemented")
+ # # => ["is invalid", "must be implemented"]
+ #
+ # person.errors.messages
+ # # => {:name=>["is invalid", "must be implemented"]}
+ #
+ # person.errors.details
+ # # => {:name=>[{error: :not_implemented}, {error: :invalid}]}
+ #
+ # If +message+ is a symbol, it will be translated using the appropriate
+ # scope (see +generate_message+).
+ #
+ # If +message+ is a proc, it will be called, allowing for things like
+ # Time.now to be used within an error.
+ #
+ # If the :strict option is set to +true+, it will raise
+ # ActiveModel::StrictValidationFailed instead of adding the error.
+ # :strict option can also be set to any other exception.
+ #
+ # person.errors.add(:name, :invalid, strict: true)
+ # # => ActiveModel::StrictValidationFailed: Name is invalid
+ # person.errors.add(:name, :invalid, strict: NameIsInvalid)
+ # # => NameIsInvalid: Name is invalid
+ #
+ # person.errors.messages # => {}
+ #
+ # +attribute+ should be set to :base if the error is not
+ # directly associated with a single attribute.
+ #
+ # person.errors.add(:base, :name_or_email_blank,
+ # message: "either name or email must be present")
+ # person.errors.messages
+ # # => {:base=>["either name or email must be present"]}
+ # person.errors.details
+ # # => {:base=>[{error: :name_or_email_blank}]}
+ def add: (untyped attribute, ?::Symbol | ::String | ^(untyped base, ::Hash[untyped, untyped]) -> (::Symbol | ::String) type, ?::Hash[untyped, untyped] options) -> void
+ end
+end