diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index e7a9676..a71c339 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -302,6 +302,19 @@ module ActiveRecord :equal_to => '==', :less_than => '<', :less_than_or_equal_to => '<=', :odd => 'odd?', :even => 'even?' }.freeze + # Returns a hash of what validations will be applied to this model. + # + # class Person < ActiveRecord::Base + # validates_uniqueness_of :name + # validates_presence_of :name, :city + # end + # + # Person.validations + # => {:uniqueness => [:name], :presence => [:name, :city]} + def validations() + @validations||{} + end + # Adds a validation method or block to the class. This is useful when # overriding the +validate+ instance method becomes too unwieldy and # you're looking for more descriptive declaration of your validations. @@ -402,6 +415,8 @@ module ActiveRecord record.errors.add(attr_name, message) end end + + add_validation(:confirmation, attr_names) end # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example: @@ -445,6 +460,8 @@ module ActiveRecord record.errors.add(attr_name, message) end end + + add_validation(:acceptance, attr_names) end # Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example: @@ -478,6 +495,8 @@ module ActiveRecord send(validation_method(configuration[:on]), configuration) do |record| record.errors.add_on_blank(attr_names, configuration[:message]) end + + add_validation(:presence, attr_names) end # Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time: @@ -568,6 +587,8 @@ module ActiveRecord end end end + + add_validation(:length, [attrs.first]) end alias_method :validates_size_of, :validates_length_of @@ -667,6 +688,7 @@ module ActiveRecord end end end + add_validation(:uniqueness, attr_names) end @@ -705,6 +727,8 @@ module ActiveRecord record.errors.add(attr_name, message) end end + + add_validation(:format, attr_names) end # Validates whether the value of the specified attribute is available in a particular enumerable object. @@ -740,6 +764,8 @@ module ActiveRecord record.errors.add(attr_name, message) end end + + add_validation(:inclusion, attr_names) end # Validates that the value of the specified attribute is not in a particular enumerable object. @@ -775,6 +801,8 @@ module ActiveRecord record.errors.add(attr_name, message) end end + + add_validation(:exclusion, attr_names) end # Validates whether the associated object or objects are all valid themselves. Works with any kind of association. @@ -818,6 +846,8 @@ module ActiveRecord record.errors.add(attr_name, message) end end + + add_validation(:associated, attr_names) end # Validates whether the value of the specified attribute is numeric by trying to convert it to @@ -892,6 +922,8 @@ module ActiveRecord end end end + + add_validation(:numericality, attr_names) end # Creates an object just like Base.create but calls save! instead of save @@ -908,6 +940,13 @@ module ActiveRecord end private + # Keep track of what validations will be applied to what attributes on this model. + def add_validation(type, additions) + @validations ||= {} + @validations[type] ||= [] + @validations[type] += additions + end + def validation_method(on) case on when :save then :validate diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 4b2d28c..013921f 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -54,6 +54,20 @@ end class Thaumaturgist < IneptWizard end +class UnvalidatedThing < ActiveRecord::Base +end + +class MultipleValidatedThing < ActiveRecord::Base + validates_uniqueness_of :name, :city + validates_presence_of :name, :city + validates_format_of :name, :with => /.*/ + validates_numericality_of :age + validates_exclusion_of :age, :in => 30..60 + validates_inclusion_of :age, :in => 0..30 + validates_length_of :name, :maximum => 25 + validates_confirmation_of :password + validates_acceptance_of :terms +end class ValidationsTest < ActiveRecord::TestCase fixtures :topics, :developers, 'warehouse-things' @@ -1376,6 +1390,23 @@ class ValidationsTest < ActiveRecord::TestCase assert t.valid?, "A topic with an important title and author should be valid" end + def test_validations_hash + assert_equal({}, UnvalidatedThing.validations) + assert_equal({:uniqueness => [:city]}, IneptWizard.validations) + assert_equal({:uniqueness => [:name]}, Wizard.validations) + assert_equal({:acceptance => [:author_name]}, PlagiarizedReply.validations) + assert_equal({:uniqueness => [:content]}, UniqueReply.validations) + assert_equal({:uniqueness => [:name, :city], + :presence => [:name, :city], + :format => [:name], + :numericality => [:age], + :exclusion => [:age], + :inclusion => [:age], + :length => [:name], + :confirmation => [:password], + :acceptance => [:terms]}, MultipleValidatedThing.validations) + end + private def with_kcode(kcode) if RUBY_VERSION < '1.9'