diff options
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/CHANGELOG.md | 68 | ||||
-rw-r--r-- | activemodel/README.rdoc | 2 | ||||
-rw-r--r-- | activemodel/lib/active_model/conversion.rb | 2 | ||||
-rw-r--r-- | activemodel/lib/active_model/dirty.rb | 2 | ||||
-rw-r--r-- | activemodel/lib/active_model/errors.rb | 16 | ||||
-rw-r--r-- | activemodel/lib/active_model/secure_password.rb | 33 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations.rb | 48 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/confirmation.rb | 6 | ||||
-rw-r--r-- | activemodel/lib/active_model/version.rb | 13 | ||||
-rw-r--r-- | activemodel/test/cases/attribute_methods_test.rb | 2 | ||||
-rw-r--r-- | activemodel/test/cases/callbacks_test.rb | 2 | ||||
-rw-r--r-- | activemodel/test/cases/errors_test.rb | 103 | ||||
-rw-r--r-- | activemodel/test/cases/naming_test.rb | 2 | ||||
-rw-r--r-- | activemodel/test/cases/secure_password_test.rb | 6 | ||||
-rw-r--r-- | activemodel/test/cases/validations/confirmation_validation_test.rb | 31 | ||||
-rw-r--r-- | activemodel/test/cases/validations/with_validation_test.rb | 2 | ||||
-rw-r--r-- | activemodel/test/cases/validations_test.rb | 8 |
17 files changed, 258 insertions, 88 deletions
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 1fe6dbd4d9..9aee47bd52 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,5 +1,69 @@ ## Rails 4.0.0 (unreleased) ## +* Add `ActiveModel::Errors#full_messages_for`, to return all the error messages + for a given attribute. + + class Person + include ActiveModel::Validations + + attr_reader :name, :email + validates_presence_of :name, :email + end + + person = Person.new + person.valid? # => false + person.errors.full_messages_for(:name) # => ["Name can't be blank"] + + *Volodymyr Shatsky* + +* Added a method so that validations can be easily cleared on a model. + For example: + + class Person + include ActiveModel::Validations + + validates_uniqueness_of :first_name + validate :cannot_be_robot + + def cannot_be_robot + errors.add(:base, 'A person cannot be a robot') if person_is_robot + end + end + + Now, if someone runs `Person.clear_validators!`, then the following occurs: + + Person.validators # => [] + Person._validate_callbacks.empty? # => true + + *John Wang* + +* `has_secure_password` does not fail the confirmation validation + when assigning empty String to `password` and `password_confirmation`. + + Example: + + # Given User has_secure_password. + @user.password = "" + @user.password_confirmation = "" + @user.valid?(:update) # used to be false + + *Yves Senn* + +* `validates_confirmation_of` does not override writer methods for + the confirmation attribute if no reader is defined. + + Example: + + class Blog + def title=(new_title) + @title = new_title.downcase + end + + # previously this would override the setter above. + validates_confirmation_of :title + end + + *Yves Senn* ## Rails 4.0.0.beta1 (February 25, 2013) ## @@ -43,7 +107,7 @@ *Yves Senn* -* Use BCrypt's `MIN_COST` in the test environment for speedier tests when using `has_secure_pasword`. +* Use BCrypt's `MIN_COST` in the test environment for speedier tests when using `has_secure_password`. *Brian Cardarella + Jeremy Kemper + Trevor Turk* @@ -84,7 +148,7 @@ * Changed `ActiveModel::Serializers::Xml::Serializer#add_associations` to by default propagate `:skip_types, :dasherize, :camelize` keys to included associations. - It can be overriden on each association by explicitly specifying the option on one + It can be overridden on each association by explicitly specifying the option on one or more associations *Anthony Alberto* diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc index 1b1fe2fa2b..a66225319d 100644 --- a/activemodel/README.rdoc +++ b/activemodel/README.rdoc @@ -2,7 +2,7 @@ Active Model provides a known set of interfaces for usage in model classes. They allow for Action Pack helpers to interact with non-Active Record models, -for example. Active Model also helps building custom ORMs for use outside of +for example. Active Model also helps with building custom ORMs for use outside of the Rails framework. Prior to Rails 3.0, if a plugin or gem developer wanted to have an object diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index 1f5d23dd8e..21e4eb3c86 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -1,5 +1,5 @@ module ActiveModel - # == Active \Model Conversions + # == Active \Model Conversion # # Handles default conversions: to_model, to_key, to_param, and to_partial_path. # diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb index 6e67cd2285..789bdd74bf 100644 --- a/activemodel/lib/active_model/dirty.rb +++ b/activemodel/lib/active_model/dirty.rb @@ -46,7 +46,7 @@ module ActiveModel # # A newly instantiated object is unchanged: # - # person = Person.find_by_name('Uncle Bob') + # person = Person.find_by(name: 'Uncle Bob') # person.changed? # => false # # Change the name: diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 963e52bff3..b60458b3c6 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -12,7 +12,6 @@ module ActiveModel # A minimal implementation could be: # # class Person - # # # Required dependency for ActiveModel::Errors # extend ActiveModel::Naming # @@ -40,7 +39,6 @@ module ActiveModel # def Person.lookup_ancestors # [self] # end - # # end # # The last three methods are required in your object for Errors to be @@ -352,6 +350,20 @@ module ActiveModel map { |attribute, message| full_message(attribute, message) } end + # Returns all the full error messages for a given attribute in an array. + # + # class Person + # validates_presence_of :name, :email + # validates_length_of :name, in: 5..30 + # end + # + # person = Person.create() + # person.errors.full_messages_for(:name) + # # => ["Name is too short (minimum is 5 characters)", "Name can't be blank"] + def full_messages_for(attribute) + (get(attribute) || []).map { |message| full_message(attribute, message) } + end + # Returns a full message for a given attribute. # # person.errors.full_message(:name, 'is invalid') # => "Name is invalid" diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb index 6644b60609..de8a641924 100644 --- a/activemodel/lib/active_model/secure_password.rb +++ b/activemodel/lib/active_model/secure_password.rb @@ -30,24 +30,31 @@ module ActiveModel # end # # user = User.new(name: 'david', password: '', password_confirmation: 'nomatch') - # user.save # => false, password required + # user.save # => false, password required # user.password = 'mUc3m00RsqyRe' - # user.save # => false, confirmation doesn't match + # user.save # => false, confirmation doesn't match # user.password_confirmation = 'mUc3m00RsqyRe' - # user.save # => true - # user.authenticate('notright') # => false - # user.authenticate('mUc3m00RsqyRe') # => user - # User.find_by_name('david').try(:authenticate, 'notright') # => false - # User.find_by_name('david').try(:authenticate, 'mUc3m00RsqyRe') # => user + # user.save # => true + # user.authenticate('notright') # => false + # user.authenticate('mUc3m00RsqyRe') # => user + # User.find_by(name: 'david').try(:authenticate, 'notright') # => false + # User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user def has_secure_password(options = {}) # Load bcrypt-ruby only when has_secure_password is used. # This is to avoid ActiveModel (and by extension the entire framework) # being dependent on a binary library. - gem 'bcrypt-ruby', '~> 3.0.0' - require 'bcrypt' + begin + gem 'bcrypt-ruby', '~> 3.0.0' + require 'bcrypt' + rescue LoadError + $stderr.puts "You don't have bcrypt-ruby installed in your application. Please add it to your Gemfile and run bundle install" + raise + end attr_reader :password + include InstanceMethodsOnActivation + if options.fetch(:validations, true) validates_confirmation_of :password validates_presence_of :password, :on => :create @@ -55,8 +62,6 @@ module ActiveModel before_create { raise "Password digest missing on new record" if password_digest.blank? } end - include InstanceMethodsOnActivation - if respond_to?(:attributes_protected_by_default) def self.attributes_protected_by_default #:nodoc: super + ['password_digest'] @@ -99,6 +104,12 @@ module ActiveModel self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost) end end + + def password_confirmation=(unencrypted_password) + unless unencrypted_password.blank? + @password_confirmation = unencrypted_password + end + end end end end diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 2db4a25f61..714cc95b9a 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -169,6 +169,49 @@ module ActiveModel _validators.values.flatten.uniq end + # Clears all of the validators and validations. + # + # Note that this will clear anything that is being used to validate + # the model for both the +validates_with+ and +validate+ methods. + # It clears the validators that are created with an invocation of + # +validates_with+ and the callbacks that are set by an invocation + # of +validate+. + # + # class Person + # include ActiveModel::Validations + # + # validates_with MyValidator + # validates_with OtherValidator, on: :create + # validates_with StrictValidator, strict: true + # validate :cannot_be_robot + # + # def cannot_be_robot + # errors.add(:base, 'A person cannot be a robot') if person_is_robot + # end + # end + # + # Person.validators + # # => [ + # # #<MyValidator:0x007fbff403e808 @options={}>, + # # #<OtherValidator:0x007fbff403d930 @options={on: :create}>, + # # #<StrictValidator:0x007fbff3204a30 @options={strict:true}> + # # ] + # + # If one runs Person.clear_validators! 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 + # so that: + # + # Person._validate_callbacks.empty? # => true + # + def clear_validators! + reset_callbacks(:validate) + _validators.clear + end + # List all validators that are being used to validate a specific attribute. # # class Person @@ -333,7 +376,4 @@ module ActiveModel end end -Dir[File.dirname(__FILE__) + "/validations/*.rb"].sort.each do |path| - filename = File.basename(path) - require "active_model/validations/#{filename}" -end +Dir[File.dirname(__FILE__) + "/validations/*.rb"].each { |file| require file } diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb index 3a3abce364..d14fb4dc53 100644 --- a/activemodel/lib/active_model/validations/confirmation.rb +++ b/activemodel/lib/active_model/validations/confirmation.rb @@ -10,9 +10,13 @@ module ActiveModel end def setup(klass) - klass.send(:attr_accessor, *attributes.map do |attribute| + klass.send(:attr_reader, *attributes.map do |attribute| :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation") end.compact) + + klass.send(:attr_writer, *attributes.map do |attribute| + :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=") + end.compact) end end diff --git a/activemodel/lib/active_model/version.rb b/activemodel/lib/active_model/version.rb index 7586b02037..35c4b30999 100644 --- a/activemodel/lib/active_model/version.rb +++ b/activemodel/lib/active_model/version.rb @@ -1,10 +1,11 @@ module ActiveModel - module VERSION #:nodoc: - MAJOR = 4 - MINOR = 0 - TINY = 0 - PRE = "beta1" + # Returns the version of the currently loaded ActiveModel as a Gem::Version + def self.version + Gem::Version.new "4.0.0.beta1" + end - STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') + module VERSION #:nodoc: + MAJOR, MINOR, TINY, PRE = ActiveModel.version.segments + STRING = ActiveModel.version.to_s end end diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb index baaf842222..d3ec78157c 100644 --- a/activemodel/test/cases/attribute_methods_test.rb +++ b/activemodel/test/cases/attribute_methods_test.rb @@ -194,7 +194,7 @@ class AttributeMethodsTest < ActiveModel::TestCase assert_raises(NoMethodError) { ModelWithAttributes.new.foo } end - test 'acessing a suffixed attribute' do + test 'accessing a suffixed attribute' do m = ModelWithAttributes2.new m.attributes = { 'foo' => 'bar' } diff --git a/activemodel/test/cases/callbacks_test.rb b/activemodel/test/cases/callbacks_test.rb index 086e7266ff..c4c34b0be7 100644 --- a/activemodel/test/cases/callbacks_test.rb +++ b/activemodel/test/cases/callbacks_test.rb @@ -107,7 +107,7 @@ class CallbacksTest < ActiveModel::TestCase test "after_create callbacks with both callbacks declared in one line" do assert_equal ["callback1", "callback2"], Violin1.new.create.history end - test "after_create callbacks with both callbacks declared in differnt lines" do + test "after_create callbacks with both callbacks declared in different lines" do assert_equal ["callback1", "callback2"], Violin2.new.create.history end diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index 51dcfc37d8..80ff97d03b 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -54,7 +54,7 @@ class ErrorsTest < ActiveModel::TestCase assert errors.has_key?(:foo), 'errors should have key :foo' end - test "should be able to clear the errors" do + test "clear errors" do person = Person.new person.validate! @@ -63,7 +63,7 @@ class ErrorsTest < ActiveModel::TestCase assert person.errors.empty? end - test "get returns the error by the provided key" do + test "get returns the errors for the provided key" do errors = ActiveModel::Errors.new(self) errors[:foo] = "omg" @@ -93,21 +93,7 @@ class ErrorsTest < ActiveModel::TestCase assert_equal [:foo, :baz], errors.keys end - test "as_json returns 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) - end - - test "as_json with :full_messages option" do - person = Person.new - person.validate! - - assert_equal({ name: ["name can not be nil"] }, person.errors.as_json(full_messages: true)) - end - - test "should return true if no errors" do + test "detecting whether there are errors with empty?, blank?, include?" do person = Person.new person.errors[:foo] assert person.errors.empty? @@ -115,139 +101,154 @@ class ErrorsTest < ActiveModel::TestCase assert !person.errors.include?(:foo) end - test "method validate! should work" do + 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] end - test 'should be able to assign error' do + test "assign error" do person = Person.new person.errors[:name] = 'should not be nil' assert_equal ["should not be nil"], person.errors[:name] end - test 'should be able to add an error on an attribute' do + 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] end - test "should be able to add an error with a symbol" do + test "add an error with a symbol" do person = Person.new person.errors.add(:name, :blank) message = person.errors.generate_message(:name, :blank) assert_equal [message], person.errors[:name] end - test "should be able to add an error with a proc" do + test "add an error with a proc" do person = Person.new message = Proc.new { "can not be blank" } person.errors.add(:name, message) assert_equal ["can not be blank"], person.errors[:name] end - test "added? should be true if that error was added" do + 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") end - test "added? should handle when message is a symbol" do + test "added? handles symbol message" do person = Person.new person.errors.add(:name, :blank) assert person.errors.added?(:name, :blank) end - test "added? should handle when message is a proc" do + test "added? handles proc messages" do person = Person.new message = Proc.new { "can not be blank" } person.errors.add(:name, message) assert person.errors.added?(:name, message) end - test "added? should default message to :invalid" do + test "added? defaults message to :invalid" do person = Person.new person.errors.add(:name) assert person.errors.added?(:name) end - test "added? should be true when several errors are present, and we ask for one of them" do + 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, "is invalid") assert person.errors.added?(:name, "can not be blank") end - test "added? should be false if no errors are present" do + test "added? returns false when no errors are present" do person = Person.new assert !person.errors.added?(:name) end - test "added? should be false when an error is present, but we check for another error" do + 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") end - test 'should respond to size' do + test "size calculates the number of error messages" do person = Person.new person.errors.add(:name, "can not be blank") assert_equal 1, person.errors.size end - test 'to_a should return an array' do + 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 end - test 'to_hash should return a hash' do + test "to_hash returns the error messages hash" do person = Person.new person.errors.add(:name, "can not be blank") - assert_instance_of ::Hash, person.errors.to_hash + assert_equal({ name: ["can not be blank"] }, person.errors.to_hash) end - test 'full_messages should return an array of error messages, with the attribute name included' do + 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 end - test 'full_message should return the given message if attribute equals :base' do + 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) + 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) + 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") + assert_equal [], person.errors.full_messages_for(:email) + end + + test "full_message returns the given message when attribute is :base" do person = Person.new assert_equal "press the button", person.errors.full_message(:base, "press the button") end - test 'full_message should return the given message with the attribute name included' do + 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") end - test 'should return a JSON hash representation of the errors' do + test "as_json creates a json formatted representation of the errors hash" do person = Person.new - person.errors.add(:name, "can not be blank") - person.errors.add(:name, "can not be nil") - person.errors.add(:email, "is invalid") - hash = person.errors.as_json - assert_equal ["can not be blank", "can not be nil"], hash[:name] - assert_equal ["is invalid"], hash[:email] + person.validate! + + assert_equal({ name: ["can not be nil"] }, person.errors.as_json) end - test 'should return a JSON hash representation of the errors with full messages' do + test "as_json with :full_messages option creates a json formatted representation of the errors containing complete messages" do person = Person.new - person.errors.add(:name, "can not be blank") - person.errors.add(:name, "can not be nil") - person.errors.add(:email, "is invalid") - hash = person.errors.as_json(:full_messages => true) - assert_equal ["name can not be blank", "name can not be nil"], hash[:name] - assert_equal ["email is invalid"], hash[:email] + person.validate! + + assert_equal({ name: ["name can not be nil"] }, person.errors.as_json(full_messages: true)) end - test "generate_message should work without i18n_scope" do + test "generate_message works without i18n_scope" do person = Person.new assert !Person.respond_to?(:i18n_scope) assert_nothing_raised { diff --git a/activemodel/test/cases/naming_test.rb b/activemodel/test/cases/naming_test.rb index 38ba3cc152..aa683f4152 100644 --- a/activemodel/test/cases/naming_test.rb +++ b/activemodel/test/cases/naming_test.rb @@ -245,7 +245,7 @@ class NamingHelpersTest < ActiveModel::TestCase end def test_uncountable - assert uncountable?(@uncountable), "Expected 'sheep' to be uncoutable" + assert uncountable?(@uncountable), "Expected 'sheep' to be uncountable" assert !uncountable?(@klass), "Expected 'contact' to be countable" end diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb index 7783bb25d5..02cd3b8a93 100644 --- a/activemodel/test/cases/secure_password_test.rb +++ b/activemodel/test/cases/secure_password_test.rb @@ -88,4 +88,10 @@ 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 end diff --git a/activemodel/test/cases/validations/confirmation_validation_test.rb b/activemodel/test/cases/validations/confirmation_validation_test.rb index f7556a249f..814eec3f59 100644 --- a/activemodel/test/cases/validations/confirmation_validation_test.rb +++ b/activemodel/test/cases/validations/confirmation_validation_test.rb @@ -71,4 +71,35 @@ class ConfirmationValidationTest < ActiveModel::TestCase I18n.backend = @old_backend end + test "does not override confirmation reader if present" do + klass = Class.new do + include ActiveModel::Validations + + def title_confirmation + "expected title" + end + + validates_confirmation_of :title + end + + assert_equal "expected title", klass.new.title_confirmation, + "confirmation validation should not override the reader" + end + + test "does not override confirmation writer if present" do + klass = Class.new do + include ActiveModel::Validations + + def title_confirmation=(value) + @title_confirmation = "expected title" + end + + validates_confirmation_of :title + end + + model = klass.new + model.title_confirmation = "new title" + assert_equal "expected title", model.title_confirmation, + "confirmation validation should not override the writer" + end end diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb index 457f553661..daa7a8d5c4 100644 --- a/activemodel/test/cases/validations/with_validation_test.rb +++ b/activemodel/test/cases/validations/with_validation_test.rb @@ -50,7 +50,7 @@ class ValidatesWithTest < ActiveModel::TestCase end end - test "vaidation with class that adds errors" do + test "validation with class that adds errors" do Topic.validates_with(ValidatorThatAddsErrors) topic = Topic.new assert topic.invalid?, "A class that adds errors causes the record to be invalid" diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb index a9d32808da..2934e70c2f 100644 --- a/activemodel/test/cases/validations_test.rb +++ b/activemodel/test/cases/validations_test.rb @@ -26,11 +26,11 @@ class ValidationsTest < ActiveModel::TestCase def test_single_field_validation r = Reply.new r.title = "There's no content!" - assert r.invalid?, "A reply without content shouldn't be saveable" + assert r.invalid?, "A reply without content shouldn't be savable" assert r.after_validation_performed, "after_validation callback should be called" r.content = "Messa content!" - assert r.valid?, "A reply with content should be saveable" + assert r.valid?, "A reply with content should be savable" assert r.after_validation_performed, "after_validation callback should be called" end @@ -213,7 +213,7 @@ class ValidationsTest < ActiveModel::TestCase assert_equal 'is too short (minimum is 2 characters)', t.errors[key][0] end - def test_validaton_with_if_and_on + def test_validation_with_if_and_on Topic.validates_presence_of :title, :if => Proc.new{|x| x.author_name = "bad"; true }, :on => :update t = Topic.new(:title => "") @@ -361,7 +361,7 @@ class ValidationsTest < ActiveModel::TestCase def test_dup_validity_is_independent Topic.validates_presence_of :title - topic = Topic.new("title" => "Litterature") + topic = Topic.new("title" => "Literature") topic.valid? duped = topic.dup |