aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel')
-rw-r--r--activemodel/CHANGELOG.md4
-rw-r--r--activemodel/activemodel.gemspec3
-rw-r--r--activemodel/lib/active_model/dirty.rb4
-rw-r--r--activemodel/lib/active_model/errors.rb17
-rw-r--r--activemodel/lib/active_model/type/decimal.rb4
-rw-r--r--activemodel/test/cases/errors_test.rb34
6 files changed, 62 insertions, 4 deletions
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 6048911217..0bc8728e36 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Add `#slice!` method to `ActiveModel::Errors`.
+
+ *Daniel López Prat*
+
* Fix numericality validator to still use value before type cast except Active Record.
Fixes #33651, #33686.
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index 7be466dc4c..493fca698a 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -25,5 +25,8 @@ Gem::Specification.new do |s|
"changelog_uri" => "https://github.com/rails/rails/blob/v#{version}/activemodel/CHANGELOG.md"
}
+ # NOTE: Please read our dependency guidelines before updating versions:
+ # https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves
+
s.add_dependency "activesupport", version
end
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index f0e1242554..0d9e761b1e 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -141,7 +141,9 @@ module ActiveModel
@mutations_from_database = nil
end
- def changes_applied # :nodoc:
+ # Clears dirty data and moves +changes+ to +previously_changed+ and
+ # +mutations_from_database+ to +mutations_before_last_save+ respectively.
+ def changes_applied
unless defined?(@attributes)
@previously_changed = changes
end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index af94d52d45..969effdc20 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -112,6 +112,17 @@ module ActiveModel
@details.merge!(other.details) { |_, ary1, ary2| ary1 + ary2 }
end
+ # Removes all errors except the given keys. Returns a hash containing the removed errors.
+ #
+ # person.errors.keys # => [:name, :age, :gender, :city]
+ # person.errors.slice!(:age, :gender) # => { :name=>["cannot be nil"], :city=>["cannot be nil"] }
+ # person.errors.keys # => [:age, :gender]
+ def slice!(*keys)
+ keys = keys.map(&:to_sym)
+ @details.slice!(*keys)
+ @messages.slice!(*keys)
+ end
+
# Clear the error messages.
#
# person.errors.full_messages # => ["name cannot be nil"]
@@ -327,11 +338,11 @@ module ActiveModel
# person.errors.added? :name, :too_long # => false
# person.errors.added? :name, "is too long" # => false
def added?(attribute, message = :invalid, options = {})
+ message = message.call if message.respond_to?(:call)
+
if message.is_a? Symbol
- self.details[attribute.to_sym].map { |e| e[:error] }.include? message
+ details[attribute.to_sym].include? normalize_detail(message, options)
else
- message = message.call if message.respond_to?(:call)
- message = normalize_message(attribute, message, options)
self[attribute].include? message
end
end
diff --git a/activemodel/lib/active_model/type/decimal.rb b/activemodel/lib/active_model/type/decimal.rb
index e8ee18c00e..b37dad1c41 100644
--- a/activemodel/lib/active_model/type/decimal.rb
+++ b/activemodel/lib/active_model/type/decimal.rb
@@ -12,6 +12,10 @@ module ActiveModel
:decimal
end
+ def serialize(value)
+ cast(value)
+ end
+
def type_cast_for_schema(value)
value.to_s.inspect
end
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index 41ff6443fe..f9015b869d 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -228,6 +228,16 @@ class ErrorsTest < ActiveModel::TestCase
assert_not person.errors.added?(:name)
end
+ test "added? returns false when checking for an error with an incorrect or missing option" do
+ person = Person.new
+ person.errors.add :name, :too_long, count: 25
+
+ assert person.errors.added? :name, :too_long, count: 25
+ assert_not person.errors.added? :name, :too_long, count: 24
+ assert_not person.errors.added? :name, :too_long
+ assert_not person.errors.added? :name, "is too long"
+ end
+
test "added? returns false when checking for an error by symbol and a different error with same message is present" do
I18n.backend.store_translations("en", errors: { attributes: { name: { wrong: "is wrong", used: "is wrong" } } })
person = Person.new
@@ -401,6 +411,30 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal({ name: [{ error: :blank }, { error: :invalid }] }, person.errors.details)
end
+ test "slice! removes all errors except the given keys" do
+ person = Person.new
+ person.errors.add(:name, "cannot be nil")
+ person.errors.add(:age, "cannot be nil")
+ person.errors.add(:gender, "cannot be nil")
+ person.errors.add(:city, "cannot be nil")
+
+ person.errors.slice!(:age, "gender")
+
+ assert_equal [:age, :gender], person.errors.keys
+ end
+
+ test "slice! returns the deleted errors" do
+ person = Person.new
+ person.errors.add(:name, "cannot be nil")
+ person.errors.add(:age, "cannot be nil")
+ person.errors.add(:gender, "cannot be nil")
+ person.errors.add(:city, "cannot be nil")
+
+ removed_errors = person.errors.slice!(:age, "gender")
+
+ assert_equal({ name: ["cannot be nil"], city: ["cannot be nil"] }, removed_errors)
+ end
+
test "errors are marshalable" do
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name, :invalid)