diff options
Diffstat (limited to 'activemodel')
41 files changed, 326 insertions, 231 deletions
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 42cf58a870..500d8dc42f 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,6 +1,33 @@ -* `attribute_changed?` now accepts parameters which check the old and new value of the attribute +* `#to_param` returns `nil` if `#to_key` returns `nil`. Fixes #11399. - `model.name_changed?(from: "Pete", to: "Ringo")` + *Yves Senn* + +* Ability to specify multiple contexts when defining a validation. + + Example: + + class Person + include ActiveModel::Validations + + attr_reader :name + validates_presence_of :name, on: [:verify, :approve] + end + + person = Person.new + person.valid? # => true + person.valid?(:verify) # => false + person.errors.full_messages_for(:name) # => ["Name can't be blank"] + person.valid?(:approve) # => false + person.errors.full_messages_for(:name) # => ["Name can't be blank"] + + *Vince Puzzella* + +* `attribute_changed?` now accepts a hash to check if the attribute was + changed `:from` and/or `:to` a given value. + + Example: + + model.name_changed?(from: "Pete", to: "Ringo") *Tejas Dinkar* @@ -19,8 +46,8 @@ *Bogdan Gusiev* -* Fix has_secure_password. `password_confirmation` validations are triggered - even if no `password_confirmation` is set. +* Fix `has_secure_password` not to trigger `password_confirmation` validations + if no `password_confirmation` is set. *Vladimir Kiselev* @@ -33,7 +60,7 @@ *Charles Bergeron* -* Fix regression in has_secure_password. When a password is set, but a +* Fix regression in `has_secure_password`. When a password is set, but a confirmation is an empty string, it would incorrectly save. *Steve Klabnik* and *Phillip Calvin* diff --git a/activemodel/MIT-LICENSE b/activemodel/MIT-LICENSE index 5c668d9624..d58dd9ed9b 100644 --- a/activemodel/MIT-LICENSE +++ b/activemodel/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2013 David Heinemeier Hansson +Copyright (c) 2004-2014 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc index a399fe9051..4c00755532 100644 --- a/activemodel/README.rdoc +++ b/activemodel/README.rdoc @@ -109,7 +109,7 @@ behavior out of the box: attr_reader :errors def validate! - errors.add(:name, "can not be nil") if name.nil? + errors.add(:name, "cannot be nil") if name.nil? end def self.human_attribute_name(attr, options = {}) @@ -118,7 +118,7 @@ behavior out of the box: end person.errors.full_messages - # => ["Name can not be nil"] + # => ["Name cannot be nil"] {Learn more}[link:classes/ActiveModel/Errors.html] diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index ef4f2514be..3e49c34182 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2013 David Heinemeier Hansson +# Copyright (c) 2004-2014 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -59,9 +59,9 @@ module ActiveModel end end - def eager_load! + def self.eager_load! super - ActiveModel::Serializer.eager_load! + ActiveModel::Serializers.eager_load! end end diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 2da2e8ec64..ea07c5c039 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -245,7 +245,7 @@ module ActiveModel # private # # def clear_attribute(attr) - # send("#{attr}", nil) + # send("#{attr}=", nil) # end # end def define_attribute_methods(*attr_names) diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index 6b0a752566..0a19ef686d 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -62,7 +62,7 @@ module ActiveModel # person = Person.create # person.to_param # => "1" def to_param - persisted? ? to_key.join('-') : nil + (persisted? && key = to_key) ? key.join('-') : nil end # Returns a +string+ identifying the path associated with the object. diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index 58d87e6f7f..98ffffeb10 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -136,7 +136,7 @@ module ActiveModel # person.save # person.previous_changes # => {"name" => ["bob", "robert"]} def previous_changes - @previously_changed ||= {} + @previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new end # Returns a hash of the attributes with unsaved changes indicating their original @@ -167,13 +167,13 @@ module ActiveModel # Removes current changes and makes them accessible through +previous_changes+. def changes_applied @previously_changed = changes - @changed_attributes = {} + @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new end # Removes all dirty data: current changes and previous changes def reset_changes - @previously_changed = {} - @changed_attributes = {} + @previously_changed = ActiveSupport::HashWithIndifferentAccess.new + @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new end # Handle <tt>*_change</tt> for +method_missing+. diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 97fd22f401..9c3bc913e1 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -23,7 +23,7 @@ module ActiveModel # attr_reader :errors # # def validate! - # errors.add(:name, "can not be nil") if name == nil + # errors.add(:name, "cannot be nil") if name == nil # end # # # The following methods are needed to be minimally implemented @@ -51,8 +51,8 @@ module ActiveModel # The above allows you to do: # # person = Person.new - # person.validate! # => ["can not be nil"] - # person.errors.full_messages # => ["name can not be nil"] + # person.validate! # => ["cannot be nil"] + # person.errors.full_messages # => ["name cannot be nil"] # # etc.. class Errors include Enumerable @@ -80,7 +80,7 @@ module ActiveModel # Clear the error messages. # - # person.errors.full_messages # => ["name can not be nil"] + # person.errors.full_messages # => ["name cannot be nil"] # person.errors.clear # person.errors.full_messages # => [] def clear @@ -90,19 +90,19 @@ module ActiveModel # Returns +true+ if the error messages include an error for the given key # +attribute+, +false+ otherwise. # - # person.errors.messages # => {:name=>["can not be nil"]} + # person.errors.messages # => {:name=>["cannot be nil"]} # person.errors.include?(:name) # => true # person.errors.include?(:age) # => false def include?(attribute) - (v = messages[attribute]) && v.any? + messages[attribute].present? end # aliases include? alias :has_key? :include? # Get messages for +key+. # - # person.errors.messages # => {:name=>["can not be nil"]} - # person.errors.get(:name) # => ["can not be nil"] + # person.errors.messages # => {:name=>["cannot be nil"]} + # person.errors.get(:name) # => ["cannot be nil"] # person.errors.get(:age) # => nil def get(key) messages[key] @@ -110,7 +110,7 @@ module ActiveModel # Set messages for +key+ to +value+. # - # person.errors.get(:name) # => ["can not be nil"] + # person.errors.get(:name) # => ["cannot be nil"] # person.errors.set(:name, ["can't be nil"]) # person.errors.get(:name) # => ["can't be nil"] def set(key, value) @@ -119,8 +119,8 @@ module ActiveModel # Delete messages for +key+. Returns the deleted messages. # - # person.errors.get(:name) # => ["can not be nil"] - # person.errors.delete(:name) # => ["can not be nil"] + # person.errors.get(:name) # => ["cannot be nil"] + # person.errors.delete(:name) # => ["cannot be nil"] # person.errors.get(:name) # => nil def delete(key) messages.delete(key) @@ -129,8 +129,8 @@ module ActiveModel # When passed a symbol or a name of a method, returns an array of errors # for the method. # - # person.errors[:name] # => ["can not be nil"] - # person.errors['name'] # => ["can not be nil"] + # person.errors[:name] # => ["cannot be nil"] + # person.errors['name'] # => ["cannot be nil"] def [](attribute) get(attribute.to_sym) || set(attribute.to_sym, []) end @@ -175,15 +175,15 @@ module ActiveModel # Returns all message values. # - # person.errors.messages # => {:name=>["can not be nil", "must be specified"]} - # person.errors.values # => [["can not be nil", "must be specified"]] + # person.errors.messages # => {:name=>["cannot be nil", "must be specified"]} + # person.errors.values # => [["cannot be nil", "must be specified"]] def values messages.values end # Returns all message keys. # - # person.errors.messages # => {:name=>["can not be nil", "must be specified"]} + # person.errors.messages # => {:name=>["cannot be nil", "must be specified"]} # person.errors.keys # => [:name] def keys messages.keys @@ -211,7 +211,7 @@ module ActiveModel # Returns +true+ if no errors are found, +false+ otherwise. # If the error message is a string it can be empty. # - # person.errors.full_messages # => ["name can not be nil"] + # person.errors.full_messages # => ["name cannot be nil"] # person.errors.empty? # => false def empty? all? { |k, v| v && v.empty? && !v.is_a?(String) } @@ -238,8 +238,8 @@ module ActiveModel # object. You can pass the <tt>:full_messages</tt> option. This determines # if the json object should contain full messages or not (false by default). # - # person.errors.as_json # => {:name=>["can not be nil"]} - # person.errors.as_json(full_messages: true) # => {:name=>["name can not be nil"]} + # person.errors.as_json # => {:name=>["cannot be nil"]} + # person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]} def as_json(options=nil) to_hash(options && options[:full_messages]) end @@ -247,8 +247,8 @@ module ActiveModel # Returns a Hash of attributes with their error messages. If +full_messages+ # is +true+, it will contain full messages (see +full_message+). # - # person.errors.to_hash # => {:name=>["can not be nil"]} - # person.errors.to_hash(true) # => {:name=>["name can not be nil"]} + # person.errors.to_hash # => {:name=>["cannot be nil"]} + # person.errors.to_hash(true) # => {:name=>["name cannot be nil"]} def to_hash(full_messages = false) if full_messages messages = {} diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb index 9d891b9ddc..01739d8ae4 100644 --- a/activemodel/lib/active_model/secure_password.rb +++ b/activemodel/lib/active_model/secure_password.rb @@ -57,11 +57,15 @@ module ActiveModel include InstanceMethodsOnActivation if options.fetch(:validations, true) - validates_confirmation_of :password, if: :should_confirm_password? - validates_presence_of :password, on: :create - validates_presence_of :password_confirmation, if: :should_confirm_password? + # This ensures the model has a password by checking whether the password_digest + # is present, so that this works with both new and existing records. However, + # when there is an error, the message is added to the password attribute instead + # so that the error message will make sense to the end-user. + validate do |record| + record.errors.add(:password, :blank) unless record.password_digest.present? + end - before_create { raise "Password digest missing on new record" if password_digest.blank? } + validates_confirmation_of :password, if: ->{ password.present? } end if respond_to?(:attributes_protected_by_default) @@ -100,7 +104,9 @@ module ActiveModel # user.password = 'mUc3m00RsqyRe' # user.password_digest # => "$2a$10$4LEA7r4YmNHtvlAvHhsYAeZmk/xeUVtMTYqwIvYY76EW5GUqDiP4." def password=(unencrypted_password) - unless unencrypted_password.blank? + if unencrypted_password.nil? + self.password_digest = nil + elsif unencrypted_password.present? @password = unencrypted_password cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost) @@ -110,12 +116,6 @@ module ActiveModel def password_confirmation=(unencrypted_password) @password_confirmation = unencrypted_password end - - private - - def should_confirm_password? - password_confirmation && password.present? - end end end end diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 6be44b5d63..e9674d5143 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -66,8 +66,10 @@ module ActiveModel # end # # Options: - # * <tt>:on</tt> - Specifies the context where this validation is active - # (e.g. <tt>on: :create</tt> or <tt>on: :custom_validation_context</tt>) + # * <tt>:on</tt> - Specifies the contexts where this validation is active. + # You can pass a symbol or an array of symbols. + # (e.g. <tt>on: :create</tt> or <tt>on: :custom_validation_context</tt> or + # <tt>on: [:create, :custom_validation_context]</tt>) # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+. # * <tt>:allow_blank</tt> - Skip validation if attribute is blank. # * <tt>:if</tt> - Specifies a method, proc or string to call to determine @@ -124,10 +126,10 @@ module ActiveModel # end # # Options: - # * <tt>:on</tt> - Specifies the context where this validation is active - # (e.g. <tt>on: :create</tt> or <tt>on: :custom_validation_context</tt>) - # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+. - # * <tt>:allow_blank</tt> - Skip validation if attribute is blank. + # * <tt>:on</tt> - Specifies the contexts where this validation is active. + # You can pass a symbol or an array of symbols. + # (e.g. <tt>on: :create</tt> or <tt>on: :custom_validation_context</tt> or + # <tt>on: [:create, :custom_validation_context]</tt>) # * <tt>:if</tt> - Specifies a method, proc or string to call to determine # if the validation should occur (e.g. <tt>if: :allow_validation</tt>, # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method, @@ -143,7 +145,7 @@ module ActiveModel options = options.dup options[:if] = Array(options[:if]) options[:if].unshift lambda { |o| - o.validation_context == options[:on] + Array(options[:on]).include?(o.validation_context) } end args << options @@ -199,12 +201,12 @@ module ActiveModel # # #<StrictValidator:0x007fbff3204a30 @options={strict:true}> # # ] # - # If one runs Person.clear_validators! and then checks to see what + # If one runs <tt>Person.clear_validators!</tt> and then checks to see what # validators this class has, you would obtain: # # Person.validators # => [] # - # Also, the callback set by +validate :cannot_be_robot+ will be erased + # Also, the callback set by <tt>validate :cannot_be_robot</tt> will be erased # so that: # # Person._validate_callbacks.empty? # => true diff --git a/activemodel/lib/active_model/validations/absence.rb b/activemodel/lib/active_model/validations/absence.rb index 1a1863370b..9b5416fb1d 100644 --- a/activemodel/lib/active_model/validations/absence.rb +++ b/activemodel/lib/active_model/validations/absence.rb @@ -21,7 +21,7 @@ module ActiveModel # * <tt>:message</tt> - A custom error message (default is: "must be blank"). # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+. + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+. # See <tt>ActiveModel::Validation#validates</tt> for more information def validates_absence_of(*attr_names) validates_with AbsenceValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb index 139de16326..ac5e79859b 100644 --- a/activemodel/lib/active_model/validations/acceptance.rb +++ b/activemodel/lib/active_model/validations/acceptance.rb @@ -38,8 +38,6 @@ module ActiveModel # Configuration options: # * <tt>:message</tt> - A custom error message (default is: "must be # accepted"). - # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default - # is +true+). # * <tt>:accept</tt> - Specifies value that is considered accepted. # The default value is a string "1", which makes it easy to relate to # an HTML checkbox. This should be set to +true+ if you are validating @@ -47,8 +45,8 @@ module ActiveModel # before validation. # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+. - # See <tt>ActiveModel::Validation#validates</tt> for more information + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+. + # See <tt>ActiveModel::Validation#validates</tt> for more information. def validates_acceptance_of(*attr_names) validates_with AcceptanceValidator, _merge_attributes(attr_names) end diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index b0542661af..a51523912f 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -57,7 +57,7 @@ module ActiveModel # confirmation"). # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+. + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+. # See <tt>ActiveModel::Validation#validates</tt> for more information def validates_confirmation_of(*attr_names) validates_with ConfirmationValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb index 48bf5cd802..f342d27275 100644 --- a/activemodel/lib/active_model/validations/exclusion.rb +++ b/activemodel/lib/active_model/validations/exclusion.rb @@ -34,13 +34,9 @@ module ActiveModel # <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>. # * <tt>:message</tt> - Specifies a custom error message (default is: "is # reserved"). - # * <tt>:allow_nil</tt> - If set to true, skips this validation if the - # attribute is +nil+ (default is +false+). - # * <tt>:allow_blank</tt> - If set to true, skips this validation if the - # attribute is blank(default is +false+). # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+. + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+. # See <tt>ActiveModel::Validation#validates</tt> for more information def validates_exclusion_of(*attr_names) validates_with ExclusionValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index f0fe22438f..ff3e95da34 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -91,10 +91,6 @@ module ActiveModel # # Configuration options: # * <tt>:message</tt> - A custom error message (default is: "is invalid"). - # * <tt>:allow_nil</tt> - If set to true, skips this validation if the - # attribute is +nil+ (default is +false+). - # * <tt>:allow_blank</tt> - If set to true, skips this validation if the - # attribute is blank (default is +false+). # * <tt>:with</tt> - Regular expression that if the attribute matches will # result in a successful validation. This can be provided as a proc or # lambda returning regular expression which will be called at runtime. @@ -107,7 +103,7 @@ module ActiveModel # beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>. # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+. + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+. # See <tt>ActiveModel::Validation#validates</tt> for more information def validates_format_of(*attr_names) validates_with FormatValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb index 24337614c5..c84025f083 100644 --- a/activemodel/lib/active_model/validations/inclusion.rb +++ b/activemodel/lib/active_model/validations/inclusion.rb @@ -29,17 +29,14 @@ module ActiveModel # * <tt>:in</tt> - An enumerable object of available items. This can be # supplied as a proc, lambda or symbol which returns an enumerable. If the # enumerable is a numerical range the test is performed with <tt>Range#cover?</tt>, - # otherwise with <tt>include?</tt>. + # otherwise with <tt>include?</tt>. When using a proc or lambda the instance + # under validation is passed as an argument. # * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt> # * <tt>:message</tt> - Specifies a custom error message (default is: "is # not included in the list"). - # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the - # attribute is +nil+ (default is +false+). - # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the - # attribute is blank (default is +false+). # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+. + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+. # See <tt>ActiveModel::Validation#validates</tt> for more information def validates_inclusion_of(*attr_names) validates_with InclusionValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index c8d3236463..a9fb9804d4 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -110,7 +110,7 @@ module ActiveModel # * <tt>:even</tt> - Specifies the value must be an even number. # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+ . + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+ . # See <tt>ActiveModel::Validation#validates</tt> for more information # # The following checks can also be supplied with a proc or a symbol which diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb index ab8c8359fc..5d593274eb 100644 --- a/activemodel/lib/active_model/validations/presence.rb +++ b/activemodel/lib/active_model/validations/presence.rb @@ -29,7 +29,7 @@ module ActiveModel # * <tt>:message</tt> - A custom error message (default is: "can't be blank"). # # There is also a list of default options supported by every validator: - # +:if+, +:unless+, +:on+ and +:strict+. + # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+. # See <tt>ActiveModel::Validation#validates</tt> for more information def validates_presence_of(*attr_names) validates_with PresenceValidator, _merge_attributes(attr_names) diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index bf588b7bd0..ae8d377fdf 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -83,7 +83,9 @@ module ActiveModel # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The # method, proc or string should return or evaluate to a +true+ or # +false+ value. - # * <tt>:strict</tt> - if the <tt>:strict</tt> option is set to true + # * <tt>:allow_nil</tt> - Skip validation if the attribute is +nil+. + # * <tt>:allow_blank</tt> - Skip validation if the attribute is blank. + # * <tt>:strict</tt> - If the <tt>:strict</tt> option is set to true # will raise ActiveModel::StrictValidationFailed instead of adding the error. # <tt>:strict</tt> option can also be set to any other exception. # diff --git a/activemodel/test/cases/conversion_test.rb b/activemodel/test/cases/conversion_test.rb index 3bb177591d..c5cfbf909d 100644 --- a/activemodel/test/cases/conversion_test.rb +++ b/activemodel/test/cases/conversion_test.rb @@ -24,6 +24,16 @@ class ConversionTest < ActiveModel::TestCase assert_equal "1", Contact.new(id: 1).to_param end + test "to_param returns nil if to_key is nil" do + klass = Class.new(Contact) do + def persisted? + true + end + end + + assert_nil klass.new.to_param + end + test "to_partial_path default implementation returns a string giving a relative path" do assert_equal "contacts/contact", Contact.new.to_partial_path assert_equal "helicopters/helicopter", Helicopter.new.to_partial_path, diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb index 54427a1513..8b55901a65 100644 --- a/activemodel/test/cases/dirty_test.rb +++ b/activemodel/test/cases/dirty_test.rb @@ -83,6 +83,14 @@ class DirtyTest < ActiveModel::TestCase assert_not_nil @model.changes['name'] end + test "be consistent with symbols arguments after the changes are applied" do + @model.name = "David" + assert @model.attribute_changed?(:name) + @model.save + @model.name = 'Rafael' + assert @model.attribute_changed?(:name) + end + test "attribute mutation" do @model.instance_variable_set("@name", "Yam") assert !@model.name_changed? diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index 4e07e0e00b..def28578f8 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -11,7 +11,7 @@ class ErrorsTest < ActiveModel::TestCase attr_reader :errors def validate! - errors.add(:name, "can not be nil") if name == nil + errors.add(:name, "cannot be nil") if name == nil end def read_attribute_for_validation(attr) @@ -51,7 +51,12 @@ class ErrorsTest < ActiveModel::TestCase def test_has_key? errors = ActiveModel::Errors.new(self) errors[:foo] = 'omg' - assert errors.has_key?(:foo), 'errors should have key :foo' + assert_equal true, errors.has_key?(:foo), 'errors should have key :foo' + end + + def test_has_no_key + errors = ActiveModel::Errors.new(self) + assert_equal false, errors.has_key?(:name), 'errors should not have key :name' end test "clear errors" do @@ -104,8 +109,8 @@ class ErrorsTest < ActiveModel::TestCase test "adding errors using conditionals with Person#validate!" do person = Person.new person.validate! - assert_equal ["name can not be nil"], person.errors.full_messages - assert_equal ["can not be nil"], person.errors[:name] + assert_equal ["name cannot be nil"], person.errors.full_messages + assert_equal ["cannot be nil"], person.errors[:name] end test "assign error" do @@ -116,8 +121,8 @@ class ErrorsTest < ActiveModel::TestCase test "add an error message on a specific attribute" do person = Person.new - person.errors.add(:name, "can not be blank") - assert_equal ["can not be blank"], person.errors[:name] + person.errors.add(:name, "cannot be blank") + assert_equal ["cannot be blank"], person.errors[:name] end test "add an error with a symbol" do @@ -129,15 +134,15 @@ class ErrorsTest < ActiveModel::TestCase test "add an error with a proc" do person = Person.new - message = Proc.new { "can not be blank" } + message = Proc.new { "cannot be blank" } person.errors.add(:name, message) - assert_equal ["can not be blank"], person.errors[:name] + assert_equal ["cannot be blank"], person.errors[:name] end test "added? detects if a specific error was added to the object" do person = Person.new - person.errors.add(:name, "can not be blank") - assert person.errors.added?(:name, "can not be blank") + person.errors.add(:name, "cannot be blank") + assert person.errors.added?(:name, "cannot be blank") end test "added? handles symbol message" do @@ -148,7 +153,7 @@ class ErrorsTest < ActiveModel::TestCase test "added? handles proc messages" do person = Person.new - message = Proc.new { "can not be blank" } + message = Proc.new { "cannot be blank" } person.errors.add(:name, message) assert person.errors.added?(:name, message) end @@ -161,9 +166,9 @@ class ErrorsTest < ActiveModel::TestCase test "added? matches the given message when several errors are present for the same attribute" do person = Person.new - person.errors.add(:name, "can not be blank") + person.errors.add(:name, "cannot be blank") person.errors.add(:name, "is invalid") - assert person.errors.added?(:name, "can not be blank") + assert person.errors.added?(:name, "cannot be blank") end test "added? returns false when no errors are present" do @@ -174,52 +179,52 @@ class ErrorsTest < ActiveModel::TestCase test "added? returns false when checking a nonexisting error and other errors are present for the given attribute" do person = Person.new person.errors.add(:name, "is invalid") - assert !person.errors.added?(:name, "can not be blank") + assert !person.errors.added?(:name, "cannot be blank") end test "size calculates the number of error messages" do person = Person.new - person.errors.add(:name, "can not be blank") + person.errors.add(:name, "cannot be blank") assert_equal 1, person.errors.size end test "to_a returns the list of errors with complete messages containing the attribute names" do person = Person.new - person.errors.add(:name, "can not be blank") - person.errors.add(:name, "can not be nil") - assert_equal ["name can not be blank", "name can not be nil"], person.errors.to_a + person.errors.add(:name, "cannot be blank") + person.errors.add(:name, "cannot be nil") + assert_equal ["name cannot be blank", "name cannot be nil"], person.errors.to_a end test "to_hash returns the error messages hash" do person = Person.new - person.errors.add(:name, "can not be blank") - assert_equal({ name: ["can not be blank"] }, person.errors.to_hash) + person.errors.add(:name, "cannot be blank") + assert_equal({ name: ["cannot be blank"] }, person.errors.to_hash) end test "full_messages creates a list of error messages with the attribute name included" do person = Person.new - person.errors.add(:name, "can not be blank") - person.errors.add(:name, "can not be nil") - assert_equal ["name can not be blank", "name can not be nil"], person.errors.full_messages + person.errors.add(:name, "cannot be blank") + person.errors.add(:name, "cannot be nil") + assert_equal ["name cannot be blank", "name cannot be nil"], person.errors.full_messages end test "full_messages_for contains all the error messages for the given attribute" do person = Person.new - person.errors.add(:name, "can not be blank") - person.errors.add(:name, "can not be nil") - assert_equal ["name can not be blank", "name can not be nil"], person.errors.full_messages_for(:name) + person.errors.add(:name, "cannot be blank") + person.errors.add(:name, "cannot be nil") + assert_equal ["name cannot be blank", "name cannot be nil"], person.errors.full_messages_for(:name) end test "full_messages_for does not contain error messages from other attributes" do person = Person.new - person.errors.add(:name, "can not be blank") - person.errors.add(:email, "can not be blank") - assert_equal ["name can not be blank"], person.errors.full_messages_for(:name) + person.errors.add(:name, "cannot be blank") + person.errors.add(:email, "cannot be blank") + assert_equal ["name cannot be blank"], person.errors.full_messages_for(:name) end test "full_messages_for returns an empty list in case there are no errors for the given attribute" do person = Person.new - person.errors.add(:name, "can not be blank") + person.errors.add(:name, "cannot be blank") assert_equal [], person.errors.full_messages_for(:email) end @@ -230,22 +235,22 @@ class ErrorsTest < ActiveModel::TestCase test "full_message returns the given message with the attribute name included" do person = Person.new - assert_equal "name can not be blank", person.errors.full_message(:name, "can not be blank") - assert_equal "name_test can not be blank", person.errors.full_message(:name_test, "can not be blank") + assert_equal "name cannot be blank", person.errors.full_message(:name, "cannot be blank") + assert_equal "name_test cannot be blank", person.errors.full_message(:name_test, "cannot be blank") end test "as_json creates a json formatted representation of the errors hash" do person = Person.new person.validate! - assert_equal({ name: ["can not be nil"] }, person.errors.as_json) + assert_equal({ name: ["cannot be nil"] }, person.errors.as_json) end test "as_json with :full_messages option creates a json formatted representation of the errors containing complete messages" do person = Person.new person.validate! - assert_equal({ name: ["name can not be nil"] }, person.errors.as_json(full_messages: true)) + assert_equal({ name: ["name cannot be nil"] }, person.errors.as_json(full_messages: true)) end test "generate_message works without i18n_scope" do diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb index 0314803af6..82fd291064 100644 --- a/activemodel/test/cases/secure_password_test.rb +++ b/activemodel/test/cases/secure_password_test.rb @@ -1,6 +1,5 @@ require 'cases/helper' require 'models/user' -require 'models/oauthed_user' require 'models/visitor' class SecurePasswordTest < ActiveModel::TestCase @@ -9,69 +8,152 @@ class SecurePasswordTest < ActiveModel::TestCase @user = User.new @visitor = Visitor.new - @oauthed_user = OauthedUser.new + + # Simulate loading an existing user from the DB + @existing_user = User.new + @existing_user.password_digest = BCrypt::Password.create('password', cost: BCrypt::Engine::MIN_COST) end teardown do ActiveModel::SecurePassword.min_cost = false end - test "blank password" do - @user.password = @visitor.password = '' - assert !@user.valid?(:create), 'user should be invalid' + test "create and updating without validations" do assert @visitor.valid?(:create), 'visitor should be valid' - end + assert @visitor.valid?(:update), 'visitor should be valid' + + @visitor.password = '123' + @visitor.password_confirmation = '456' - test "nil password" do - @user.password = @visitor.password = nil - assert !@user.valid?(:create), 'user should be invalid' assert @visitor.valid?(:create), 'visitor should be valid' + assert @visitor.valid?(:update), 'visitor should be valid' end - test "blank password doesn't override previous password" do - @user.password = 'test' + test "create a new user with validation and a blank password" do @user.password = '' - assert_equal @user.password, 'test' + assert !@user.valid?(:create), 'user should be invalid' + assert_equal 1, @user.errors.count + assert_equal ["can't be blank"], @user.errors[:password] + end + + test "create a new user with validation and a nil password" do + @user.password = nil + assert !@user.valid?(:create), 'user should be invalid' + assert_equal 1, @user.errors.count + assert_equal ["can't be blank"], @user.errors[:password] + end + + test "create a new user with validation and a blank password confirmation" do + @user.password = 'password' + @user.password_confirmation = '' + assert !@user.valid?(:create), 'user should be invalid' + assert_equal 1, @user.errors.count + assert_equal ["doesn't match Password"], @user.errors[:password_confirmation] end - test "password must be present" do - assert !@user.valid?(:create) - assert_equal 1, @user.errors.size + test "create a new user with validation and a nil password confirmation" do + @user.password = 'password' + @user.password_confirmation = nil + assert @user.valid?(:create), 'user should be valid' end - test "match confirmation" do - @user.password = @visitor.password = "thiswillberight" - @user.password_confirmation = @visitor.password_confirmation = "wrong" + test "create a new user with validation and an incorrect password confirmation" do + @user.password = 'password' + @user.password_confirmation = 'something else' + assert !@user.valid?(:create), 'user should be invalid' + assert_equal 1, @user.errors.count + assert_equal ["doesn't match Password"], @user.errors[:password_confirmation] + end - assert !@user.valid? - assert @visitor.valid? + test "create a new user with validation and a correct password confirmation" do + @user.password = 'password' + @user.password_confirmation = 'something else' + assert !@user.valid?(:create), 'user should be invalid' + assert_equal 1, @user.errors.count + assert_equal ["doesn't match Password"], @user.errors[:password_confirmation] + end - @user.password_confirmation = "thiswillberight" + test "update an existing user with validation and no change in password" do + assert @existing_user.valid?(:update), 'user should be valid' + end - assert @user.valid? + test "updating an existing user with validation and a blank password" do + @existing_user.password = '' + assert @existing_user.valid?(:update), 'user should be valid' end - test "authenticate" do - @user.password = "secret" + test "updating an existing user with validation and a blank password and password_confirmation" do + @existing_user.password = '' + @existing_user.password_confirmation = '' + assert @existing_user.valid?(:update), 'user should be valid' + end - assert !@user.authenticate("wrong") - assert @user.authenticate("secret") + test "updating an existing user with validation and a nil password" do + @existing_user.password = nil + assert !@existing_user.valid?(:update), 'user should be invalid' + assert_equal 1, @existing_user.errors.count + assert_equal ["can't be blank"], @existing_user.errors[:password] + end + + test "updating an existing user with validation and a blank password confirmation" do + @existing_user.password = 'password' + @existing_user.password_confirmation = '' + assert !@existing_user.valid?(:update), 'user should be invalid' + assert_equal 1, @existing_user.errors.count + assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation] end - test "User should not be created with blank digest" do - assert_raise RuntimeError do - @user.run_callbacks :create - end - @user.password = "supersecretpassword" - assert_nothing_raised do - @user.run_callbacks :create - end + test "updating an existing user with validation and a nil password confirmation" do + @existing_user.password = 'password' + @existing_user.password_confirmation = nil + assert @existing_user.valid?(:update), 'user should be valid' end - test "Oauthed user can be created with blank digest" do - assert_nothing_raised do - @oauthed_user.run_callbacks :create - end + test "updating an existing user with validation and an incorrect password confirmation" do + @existing_user.password = 'password' + @existing_user.password_confirmation = 'something else' + assert !@existing_user.valid?(:update), 'user should be invalid' + assert_equal 1, @existing_user.errors.count + assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation] + end + + test "updating an existing user with validation and a correct password confirmation" do + @existing_user.password = 'password' + @existing_user.password_confirmation = 'something else' + assert !@existing_user.valid?(:update), 'user should be invalid' + assert_equal 1, @existing_user.errors.count + assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation] + end + + test "updating an existing user with validation and a blank password digest" do + @existing_user.password_digest = '' + assert !@existing_user.valid?(:update), 'user should be invalid' + assert_equal 1, @existing_user.errors.count + assert_equal ["can't be blank"], @existing_user.errors[:password] + end + + test "updating an existing user with validation and a nil password digest" do + @existing_user.password_digest = nil + assert !@existing_user.valid?(:update), 'user should be invalid' + assert_equal 1, @existing_user.errors.count + assert_equal ["can't be blank"], @existing_user.errors[:password] + end + + test "setting a blank password should not change an existing password" do + @existing_user.password = '' + assert @existing_user.password_digest == 'password' + end + + test "setting a nil password should clear an existing password" do + @existing_user.password = nil + assert_equal nil, @existing_user.password_digest + end + + test "authenticate" do + @user.password = "secret" + + assert !@user.authenticate("wrong") + assert @user.authenticate("secret") end test "Password digest cost defaults to bcrypt default cost when min_cost is false" do @@ -95,24 +177,4 @@ class SecurePasswordTest < ActiveModel::TestCase @user.password = "secret" assert_equal BCrypt::Engine::MIN_COST, @user.password_digest.cost end - - test "blank password_confirmation does not result in a confirmation error" do - @user.password = "" - @user.password_confirmation = "" - assert @user.valid?(:update), "user should be valid" - end - - test "password_confirmation validations will not be triggered if password_confirmation is not sent" do - @user.password = "password" - assert @user.valid?(:create) - end - - test "will not save if confirmation is blank but password is not" do - @user.password = "password" - @user.password_confirmation = "" - assert_not @user.valid?(:create) - - @user.password_confirmation = "password" - assert @user.valid?(:create) - end end diff --git a/activemodel/test/cases/validations/absence_validation_test.rb b/activemodel/test/cases/validations/absence_validation_test.rb index c05d71de5a..795ce16d28 100644 --- a/activemodel/test/cases/validations/absence_validation_test.rb +++ b/activemodel/test/cases/validations/absence_validation_test.rb @@ -6,9 +6,9 @@ require 'models/custom_reader' class AbsenceValidationTest < ActiveModel::TestCase teardown do - Topic.reset_callbacks(:validate) - Person.reset_callbacks(:validate) - CustomReader.reset_callbacks(:validate) + Topic.clear_validators! + Person.clear_validators! + CustomReader.clear_validators! end def test_validate_absences diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb index dc413bef30..e78aa1adaf 100644 --- a/activemodel/test/cases/validations/acceptance_validation_test.rb +++ b/activemodel/test/cases/validations/acceptance_validation_test.rb @@ -8,7 +8,7 @@ require 'models/person' class AcceptanceValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_terms_of_service_agreement_no_acceptance @@ -63,6 +63,6 @@ class AcceptanceValidationTest < ActiveModel::TestCase p.karma = "1" assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end end diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb index 5049d6dd61..1261937b56 100644 --- a/activemodel/test/cases/validations/conditional_validation_test.rb +++ b/activemodel/test/cases/validations/conditional_validation_test.rb @@ -6,7 +6,7 @@ require 'models/topic' class ConditionalValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_if_validation_using_method_true diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb index f03de2c24a..4957ba5d0a 100644 --- a/activemodel/test/cases/validations/confirmation_validation_test.rb +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -7,7 +7,7 @@ require 'models/person' class ConfirmationValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_no_title_confirmation @@ -49,7 +49,7 @@ class ConfirmationValidationTest < ActiveModel::TestCase p.karma = "None" assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end def test_title_confirmation_with_i18n_attribute diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb index 81455ba519..1ce41f9bc9 100644 --- a/activemodel/test/cases/validations/exclusion_validation_test.rb +++ b/activemodel/test/cases/validations/exclusion_validation_test.rb @@ -7,7 +7,7 @@ require 'models/person' class ExclusionValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_validates_exclusion_of @@ -50,7 +50,7 @@ class ExclusionValidationTest < ActiveModel::TestCase p.karma = "Lifo" assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end def test_validates_exclusion_of_with_lambda @@ -87,6 +87,6 @@ class ExclusionValidationTest < ActiveModel::TestCase assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end end diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb index 26e8dbf19c..0f91b73cd7 100644 --- a/activemodel/test/cases/validations/format_validation_test.rb +++ b/activemodel/test/cases/validations/format_validation_test.rb @@ -7,7 +7,7 @@ require 'models/person' class PresenceValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_validate_format @@ -68,11 +68,11 @@ class PresenceValidationTest < ActiveModel::TestCase assert t.invalid? assert_equal ["can't be Invalid title"], t.errors[:title] end - + def test_validate_format_of_with_multiline_regexp_should_raise_error assert_raise(ArgumentError) { Topic.validates_format_of(:title, with: /^Valid Title$/) } end - + def test_validate_format_of_with_multiline_regexp_and_option assert_nothing_raised(ArgumentError) do Topic.validates_format_of(:title, with: /^Valid Title$/, multiline: true) @@ -144,6 +144,6 @@ class PresenceValidationTest < ActiveModel::TestCase p.karma = "1234" assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end end diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb index 40a5aee997..93600c587a 100644 --- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb @@ -4,7 +4,7 @@ require 'models/person' class I18nGenerateMessageValidationTest < ActiveModel::TestCase def setup - Person.reset_callbacks(:validate) + Person.clear_validators! @person = Person.new end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index e29771d6b7..d10010537e 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -6,7 +6,7 @@ require 'models/person' class I18nValidationTest < ActiveModel::TestCase def setup - Person.reset_callbacks(:validate) + Person.clear_validators! @person = Person.new @old_load_path, @old_backend = I18n.load_path.dup, I18n.backend @@ -16,7 +16,7 @@ class I18nValidationTest < ActiveModel::TestCase end def teardown - Person.reset_callbacks(:validate) + Person.clear_validators! I18n.load_path.replace @old_load_path I18n.backend = @old_backend end diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb index 8b90856869..3a8f3080e1 100644 --- a/activemodel/test/cases/validations/inclusion_validation_test.rb +++ b/activemodel/test/cases/validations/inclusion_validation_test.rb @@ -8,7 +8,7 @@ require 'models/person' class InclusionValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_validates_inclusion_of_range @@ -105,7 +105,7 @@ class InclusionValidationTest < ActiveModel::TestCase p.karma = "monkey" assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end def test_validates_inclusion_of_with_lambda @@ -142,6 +142,6 @@ class InclusionValidationTest < ActiveModel::TestCase assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end end diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb index 8b2f886cc4..046ffcb16f 100644 --- a/activemodel/test/cases/validations/length_validation_test.rb +++ b/activemodel/test/cases/validations/length_validation_test.rb @@ -6,7 +6,7 @@ require 'models/person' class LengthValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_validates_length_of_with_allow_nil @@ -354,7 +354,7 @@ class LengthValidationTest < ActiveModel::TestCase p.karma = "The Smiths" assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end def test_validates_length_of_for_infinite_maxima diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb index 84332ed014..f77cf47fb7 100644 --- a/activemodel/test/cases/validations/numericality_validation_test.rb +++ b/activemodel/test/cases/validations/numericality_validation_test.rb @@ -9,7 +9,7 @@ require 'bigdecimal' class NumericalityValidationTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end NIL = [nil] @@ -157,7 +157,7 @@ class NumericalityValidationTest < ActiveModel::TestCase p.karma = "1234" assert p.valid? ensure - Person.reset_callbacks(:validate) + Person.clear_validators! end def test_validates_numericality_with_invalid_args diff --git a/activemodel/test/cases/validations/presence_validation_test.rb b/activemodel/test/cases/validations/presence_validation_test.rb index 2f228cfa83..ecf16d1e16 100644 --- a/activemodel/test/cases/validations/presence_validation_test.rb +++ b/activemodel/test/cases/validations/presence_validation_test.rb @@ -8,9 +8,9 @@ require 'models/custom_reader' class PresenceValidationTest < ActiveModel::TestCase teardown do - Topic.reset_callbacks(:validate) - Person.reset_callbacks(:validate) - CustomReader.reset_callbacks(:validate) + Topic.clear_validators! + Person.clear_validators! + CustomReader.clear_validators! end def test_validate_presences diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb index c1914b32bc..699a872e42 100644 --- a/activemodel/test/cases/validations/validates_test.rb +++ b/activemodel/test/cases/validations/validates_test.rb @@ -11,9 +11,9 @@ class ValidatesTest < ActiveModel::TestCase teardown :reset_callbacks def reset_callbacks - Person.reset_callbacks(:validate) - Topic.reset_callbacks(:validate) - PersonWithValidator.reset_callbacks(:validate) + Person.clear_validators! + Topic.clear_validators! + PersonWithValidator.clear_validators! end def test_validates_with_messages_empty diff --git a/activemodel/test/cases/validations/validations_context_test.rb b/activemodel/test/cases/validations/validations_context_test.rb index 5f99b320a6..005bf118c6 100644 --- a/activemodel/test/cases/validations/validations_context_test.rb +++ b/activemodel/test/cases/validations/validations_context_test.rb @@ -4,10 +4,8 @@ require 'cases/helper' require 'models/topic' class ValidationsContextTest < ActiveModel::TestCase - def teardown - Topic.reset_callbacks(:validate) - Topic._validators.clear + Topic.clear_validators! end ERROR_MESSAGE = "Validation error from validator" @@ -36,4 +34,17 @@ class ValidationsContextTest < ActiveModel::TestCase assert topic.invalid?(:create), "Validation does run on create if 'on' is set to create" assert topic.errors[:base].include?(ERROR_MESSAGE) end + + test "with a class that adds errors on multiple contexts and validating a new model" do + Topic.validates_with(ValidatorThatAddsErrors, on: [:context1, :context2]) + + topic = Topic.new + assert topic.valid?, "Validation ran with no context given when 'on' is set to context1 and context2" + + assert topic.invalid?(:context1), "Validation did not run on context1 when 'on' is set to context1 and context2" + assert topic.errors[:base].include?(ERROR_MESSAGE) + + assert topic.invalid?(:context2), "Validation did not run on context2 when 'on' is set to context1 and context2" + assert topic.errors[:base].include?(ERROR_MESSAGE) + end end diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb index 93716f1433..736c2deea8 100644 --- a/activemodel/test/cases/validations/with_validation_test.rb +++ b/activemodel/test/cases/validations/with_validation_test.rb @@ -6,8 +6,7 @@ require 'models/topic' class ValidatesWithTest < ActiveModel::TestCase def teardown - Topic.reset_callbacks(:validate) - Topic._validators.clear + Topic.clear_validators! end ERROR_MESSAGE = "Validation error from validator" diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index 039b6b8872..bee8ece992 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -10,17 +10,10 @@ require 'active_support/json' require 'active_support/xml_mini' class ValidationsTest < ActiveModel::TestCase - class CustomStrictValidationException < StandardError; end - def setup - Topic._validators.clear - end - - # Most of the tests mess with the validations of Topic, so lets repair it all the time. - # Other classes we mess with will be dealt with in the specific tests def teardown - Topic.reset_callbacks(:validate) + Topic.clear_validators! end def test_single_field_validation diff --git a/activemodel/test/models/oauthed_user.rb b/activemodel/test/models/oauthed_user.rb deleted file mode 100644 index 9750bc19d4..0000000000 --- a/activemodel/test/models/oauthed_user.rb +++ /dev/null @@ -1,11 +0,0 @@ -class OauthedUser - extend ActiveModel::Callbacks - include ActiveModel::Validations - include ActiveModel::SecurePassword - - define_model_callbacks :create - - has_secure_password(validations: false) - - attr_accessor :password_digest, :password_salt -end diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb index 4b11df12bf..cbe259b1ad 100644 --- a/activemodel/test/models/user.rb +++ b/activemodel/test/models/user.rb @@ -7,5 +7,5 @@ class User has_secure_password - attr_accessor :password_digest, :password_salt + attr_accessor :password_digest end |