mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add validators reflection so you can do 'Person.validators' and 'Person.validators_on(:name)'.
Signed-off-by: José Valim <jose.valim@gmail.com>
This commit is contained in:
parent
250c809246
commit
8f97e9d19a
5 changed files with 73 additions and 3 deletions
|
@ -1,4 +1,5 @@
|
|||
require 'active_support/core_ext/array/extract_options'
|
||||
require 'active_support/core_ext/class/attribute'
|
||||
require 'active_support/core_ext/hash/keys'
|
||||
require 'active_model/errors'
|
||||
|
||||
|
@ -45,6 +46,9 @@ module ActiveModel
|
|||
included do
|
||||
extend ActiveModel::Translation
|
||||
define_callbacks :validate, :scope => :name
|
||||
|
||||
class_attribute :_validators
|
||||
self._validators = Hash.new { |h,k| h[k] = [] }
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
@ -117,9 +121,20 @@ module ActiveModel
|
|||
end
|
||||
set_callback(:validate, *args, &block)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
# List all validators that being used to validate the model using +validates_with+
|
||||
# method.
|
||||
def validators
|
||||
_validators.values.flatten.uniq
|
||||
end
|
||||
|
||||
# List all validators that being used to validate a specific attribute.
|
||||
def validators_on(attribute)
|
||||
_validators[attribute.to_sym]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _merge_attributes(attr_names)
|
||||
options = attr_names.extract_options!
|
||||
options.merge(:attributes => attr_names)
|
||||
|
|
|
@ -62,6 +62,15 @@ module ActiveModel
|
|||
args.each do |klass|
|
||||
validator = klass.new(options, &block)
|
||||
validator.setup(self) if validator.respond_to?(:setup)
|
||||
|
||||
if validator.respond_to?(:attributes) && !validator.attributes.empty?
|
||||
validator.attributes.each do |attribute|
|
||||
_validators[attribute.to_sym] << validator
|
||||
end
|
||||
else
|
||||
_validators[nil] << validator
|
||||
end
|
||||
|
||||
validate(validator, options)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require "active_support/core_ext/module/anonymous"
|
||||
|
||||
module ActiveModel #:nodoc:
|
||||
# A simple base class that can be used along with
|
||||
# +ActiveModel::Validations::ClassMethods.validates_with+
|
||||
|
@ -88,11 +90,27 @@ module ActiveModel #:nodoc:
|
|||
class Validator
|
||||
attr_reader :options
|
||||
|
||||
# Returns the kind of the validator.
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# PresenceValidator.kind #=> :presence
|
||||
# UniquenessValidator.kind #=> :uniqueness
|
||||
#
|
||||
def self.kind
|
||||
@kind ||= name.split('::').last.underscore.sub(/_validator$/, '').to_sym unless anonymous?
|
||||
end
|
||||
|
||||
# Accepts options that will be made availible through the +options+ reader.
|
||||
def initialize(options)
|
||||
@options = options
|
||||
end
|
||||
|
||||
# Return the kind for this validator.
|
||||
def kind
|
||||
self.class.kind
|
||||
end
|
||||
|
||||
# Override this method in subclasses with validation logic, adding errors
|
||||
# to the records +errors+ array where necessary.
|
||||
def validate(record)
|
||||
|
|
|
@ -9,6 +9,7 @@ class ValidatesWithTest < ActiveRecord::TestCase
|
|||
|
||||
def teardown
|
||||
Topic.reset_callbacks(:validate)
|
||||
Topic._validators.clear
|
||||
end
|
||||
|
||||
ERROR_MESSAGE = "Validation error from validator"
|
||||
|
|
|
@ -10,6 +10,10 @@ require 'models/custom_reader'
|
|||
class ValidationsTest < ActiveModel::TestCase
|
||||
include ActiveModel::TestsDatabase
|
||||
|
||||
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
|
||||
|
@ -220,4 +224,27 @@ class ValidationsTest < ActiveModel::TestCase
|
|||
assert !t.valid?
|
||||
assert ["NO BLANKS HERE"], t.errors[:title]
|
||||
end
|
||||
|
||||
def test_list_of_validators_for_model
|
||||
Topic.validates_presence_of :title
|
||||
Topic.validates_length_of :title, :minimum => 2
|
||||
|
||||
assert_equal 2, Topic.validators.count
|
||||
assert_equal [:presence, :length], Topic.validators.map(&:kind)
|
||||
end
|
||||
|
||||
def test_list_of_validators_on_an_attribute
|
||||
Topic.validates_presence_of :title, :content
|
||||
Topic.validates_length_of :title, :minimum => 2
|
||||
|
||||
assert_equal 2, Topic.validators_on(:title).count
|
||||
assert_equal [:presence, :length], Topic.validators_on(:title).map(&:kind)
|
||||
assert_equal 1, Topic.validators_on(:content).count
|
||||
assert_equal [:presence], Topic.validators_on(:content).map(&:kind)
|
||||
end
|
||||
|
||||
def test_accessing_instance_of_validator_on_an_attribute
|
||||
Topic.validates_length_of :title, :minimum => 10
|
||||
assert_equal 10, Topic.validators_on(:title).first.options[:minimum]
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue