Permit frozen models to be validated (#47969)

* Permit frozen models to be validated

* Remove initialize method since it's not needed

 Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
This commit is contained in:
Nick Pezza 2024-08-16 11:24:39 -04:00 committed by GitHub
parent c0effe0479
commit afecc8fd6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 23 deletions

View File

@ -45,27 +45,6 @@ module ActiveModel
extend HelperMethods
include HelperMethods
##
# :method: validation_context
# Returns the context when running validations.
#
# This is useful when running validations except a certain context (opposite to the +on+ option).
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# validates :name, presence: true, if: -> { validation_context != :custom }
# end
#
# person = Person.new
# person.valid? #=> false
# person.valid?(:new) #=> false
# person.valid?(:custom) #=> true
##
attr_accessor :validation_context
private :validation_context=
define_callbacks :validate, scope: :name
class_attribute :_validators, instance_writer: false, default: Hash.new { |h, k| h[k] = [] }
@ -361,15 +340,23 @@ module ActiveModel
# person.valid? # => true
# person.valid?(:new) # => false
def valid?(context = nil)
current_context, self.validation_context = validation_context, context
current_context = validation_context
context_for_validation.context = context
errors.clear
run_validations!
ensure
self.validation_context = current_context
context_for_validation.context = current_context
end
alias_method :validate, :valid?
def freeze
errors
context_for_validation
super
end
# Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
# added, +false+ otherwise.
#
@ -430,7 +417,34 @@ module ActiveModel
# end
alias :read_attribute_for_validation :send
# Returns the context when running validations.
#
# This is useful when running validations except a certain context (opposite to the +on+ option).
#
# class Person
# include ActiveModel::Validations
#
# attr_accessor :name
# validates :name, presence: true, if: -> { validation_context != :custom }
# end
#
# person = Person.new
# person.valid? #=> false
# person.valid?(:new) #=> false
# person.valid?(:custom) #=> true
def validation_context
context_for_validation.context
end
private
def validation_context=(context)
context_for_validation.context = context
end
def context_for_validation
@context_for_validation ||= ValidationContext.new
end
def init_internals
super
@errors = nil
@ -466,6 +480,10 @@ module ActiveModel
super(I18n.t(:"#{@model.class.i18n_scope}.errors.messages.model_invalid", errors: errors, default: :"errors.messages.model_invalid"))
end
end
class ValidationContext # :nodoc:
attr_accessor :context
end
end
Dir[File.expand_path("validations/*.rb", __dir__)].each { |file| require file }

View File

@ -3,6 +3,7 @@
require "cases/helper"
require "models/topic"
require "models/person"
require "models/reply"
require "models/custom_reader"
@ -14,6 +15,7 @@ class ValidationsTest < ActiveModel::TestCase
def teardown
Topic.clear_validators!
Person.clear_validators!
end
def test_single_field_validation
@ -453,4 +455,11 @@ class ValidationsTest < ActiveModel::TestCase
assert_predicate t, :invalid?
assert_equal ["Title is missing. You have failed me for the last time, Admiral."], t.errors[:title]
end
def test_frozen_models_can_be_validated
Person.validates :title, presence: true
person = Person.new.freeze
assert_predicate person, :frozen?
assert_not person.valid?
end
end