diff options
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/CHANGELOG.md | 4 | ||||
-rw-r--r-- | activemodel/activemodel.gemspec | 3 | ||||
-rw-r--r-- | activemodel/lib/active_model/dirty.rb | 4 | ||||
-rw-r--r-- | activemodel/lib/active_model/errors.rb | 17 | ||||
-rw-r--r-- | activemodel/lib/active_model/type/decimal.rb | 4 | ||||
-rw-r--r-- | activemodel/test/cases/errors_test.rb | 34 |
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) |