mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
deprecate Validator#setup (to get rid of a respond_to call). validators do their setup in their constructor now.
This commit is contained in:
parent
30d28b1958
commit
7d84c3a2f7
8 changed files with 61 additions and 42 deletions
|
@ -1,3 +1,5 @@
|
|||
* No changes.
|
||||
* Deprecate `Validator#setup`. This should be done manually now in the validator's constructor.
|
||||
|
||||
*Nick Sutterer*
|
||||
|
||||
Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/activemodel/CHANGELOG.md) for previous changes.
|
||||
|
|
|
@ -4,6 +4,7 @@ module ActiveModel
|
|||
class AcceptanceValidator < EachValidator # :nodoc:
|
||||
def initialize(options)
|
||||
super({ allow_nil: true, accept: "1" }.merge!(options))
|
||||
setup!(options[:class])
|
||||
end
|
||||
|
||||
def validate_each(record, attribute, value)
|
||||
|
@ -12,7 +13,8 @@ module ActiveModel
|
|||
end
|
||||
end
|
||||
|
||||
def setup(klass)
|
||||
private
|
||||
def setup!(klass)
|
||||
attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
|
||||
attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
|
||||
klass.send(:attr_reader, *attr_readers)
|
||||
|
|
|
@ -2,6 +2,11 @@ module ActiveModel
|
|||
|
||||
module Validations
|
||||
class ConfirmationValidator < EachValidator # :nodoc:
|
||||
def initialize(options)
|
||||
super
|
||||
setup!(options[:class])
|
||||
end
|
||||
|
||||
def validate_each(record, attribute, value)
|
||||
if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed)
|
||||
human_attribute_name = record.class.human_attribute_name(attribute)
|
||||
|
@ -9,7 +14,8 @@ module ActiveModel
|
|||
end
|
||||
end
|
||||
|
||||
def setup(klass)
|
||||
private
|
||||
def setup!(klass)
|
||||
klass.send(:attr_reader, *attributes.map do |attribute|
|
||||
:"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
|
||||
end.compact)
|
||||
|
|
|
@ -83,9 +83,10 @@ module ActiveModel
|
|||
# end
|
||||
def validates_with(*args, &block)
|
||||
options = args.extract_options!
|
||||
options[:class] = self
|
||||
|
||||
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|
|
||||
|
|
|
@ -82,18 +82,16 @@ module ActiveModel
|
|||
# validates :title, presence: true
|
||||
# end
|
||||
#
|
||||
# Validator may also define a +setup+ instance method which will get called
|
||||
# with the class that using that validator as its argument. This can be
|
||||
# useful when there are prerequisites such as an +attr_accessor+ being present.
|
||||
# It can be useful to access the class that is using that validator when there are prerequisites such
|
||||
# as an +attr_accessor+ being present. This class is accessable via +options[:class]+ in the constructor.
|
||||
# To setup your validator override the constructor.
|
||||
#
|
||||
# class MyValidator < ActiveModel::Validator
|
||||
# def setup(klass)
|
||||
# klass.send :attr_accessor, :custom_attribute
|
||||
# def initialize(options={})
|
||||
# super
|
||||
# options[:class].send :attr_accessor, :custom_attribute
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# This setup method is only called when used with validation macros or the
|
||||
# class level <tt>validates_with</tt> method.
|
||||
class Validator
|
||||
attr_reader :options
|
||||
|
||||
|
@ -107,7 +105,8 @@ module ActiveModel
|
|||
|
||||
# Accepts options that will be made available through the +options+ reader.
|
||||
def initialize(options = {})
|
||||
@options = options.freeze
|
||||
@options = options.except(:class).freeze
|
||||
deprecated_setup(options)
|
||||
end
|
||||
|
||||
# Return the kind for this validator.
|
||||
|
@ -123,6 +122,21 @@ module ActiveModel
|
|||
def validate(record)
|
||||
raise NotImplementedError, "Subclasses must implement a validate(record) method."
|
||||
end
|
||||
|
||||
private
|
||||
def deprecated_setup(options) # TODO: remove me in 4.2.
|
||||
return unless respond_to?(:setup)
|
||||
ActiveSupport::Deprecation.warn "The `Validator#setup` instance method is deprecated and will be removed on Rails 4.2. Do your setup in the constructor instead:
|
||||
|
||||
class MyValidator < ActiveModel::Validator
|
||||
def initialize(options={})
|
||||
super
|
||||
options[:class].send :attr_accessor, :custom_attribute
|
||||
end
|
||||
end
|
||||
"
|
||||
setup(options[:class])
|
||||
end
|
||||
end
|
||||
|
||||
# +EachValidator+ is a validator which iterates through the attributes given
|
||||
|
|
|
@ -100,35 +100,13 @@ class ValidatesWithTest < ActiveModel::TestCase
|
|||
test "passes all configuration options to the validator class" do
|
||||
topic = Topic.new
|
||||
validator = mock()
|
||||
validator.expects(:new).with(foo: :bar, if: "1 == 1").returns(validator)
|
||||
validator.expects(:new).with(foo: :bar, if: "1 == 1", class: Topic).returns(validator)
|
||||
validator.expects(:validate).with(topic)
|
||||
|
||||
Topic.validates_with(validator, if: "1 == 1", foo: :bar)
|
||||
assert topic.valid?
|
||||
end
|
||||
|
||||
test "calls setup method of validator passing in self when validator has setup method" do
|
||||
topic = Topic.new
|
||||
validator = stub_everything
|
||||
validator.stubs(:new).returns(validator)
|
||||
validator.stubs(:validate)
|
||||
validator.stubs(:respond_to?).with(:setup).returns(true)
|
||||
validator.expects(:setup).with(Topic).once
|
||||
Topic.validates_with(validator)
|
||||
assert topic.valid?
|
||||
end
|
||||
|
||||
test "doesn't call setup method of validator when validator has no setup method" do
|
||||
topic = Topic.new
|
||||
validator = stub_everything
|
||||
validator.stubs(:new).returns(validator)
|
||||
validator.stubs(:validate)
|
||||
validator.stubs(:respond_to?).with(:setup).returns(false)
|
||||
validator.expects(:setup).with(Topic).never
|
||||
Topic.validates_with(validator)
|
||||
assert topic.valid?
|
||||
end
|
||||
|
||||
test "validates_with with options" do
|
||||
Topic.validates_with(ValidatorThatValidatesOptions, field: :first_name)
|
||||
topic = Topic.new
|
||||
|
|
|
@ -373,4 +373,25 @@ class ValidationsTest < ActiveModel::TestCase
|
|||
assert topic.invalid?
|
||||
assert duped.valid?
|
||||
end
|
||||
|
||||
# validator test:
|
||||
def test_setup_is_deprecated_but_still_receives_klass # TODO: remove me in 4.2.
|
||||
validator_class = Class.new(ActiveModel::Validator) do
|
||||
def setup(klass)
|
||||
@old_klass = klass
|
||||
end
|
||||
|
||||
def validate(*)
|
||||
@old_klass == Topic or raise "#setup didn't work"
|
||||
end
|
||||
end
|
||||
|
||||
assert_deprecated do
|
||||
Topic.validates_with validator_class
|
||||
end
|
||||
|
||||
t = Topic.new
|
||||
t.valid?
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -7,11 +7,7 @@ module ActiveRecord
|
|||
"Pass a callable instead: `conditions: -> { where(approved: true) }`"
|
||||
end
|
||||
super({ case_sensitive: true }.merge!(options))
|
||||
end
|
||||
|
||||
# Unfortunately, we have to tie Uniqueness validators to a class.
|
||||
def setup(klass)
|
||||
@klass = klass
|
||||
@klass = options[:class]
|
||||
end
|
||||
|
||||
def validate_each(record, attribute, value)
|
||||
|
@ -34,7 +30,6 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
protected
|
||||
|
||||
# The check for an existing value should be run from a class that
|
||||
# isn't abstract. This means working down from the current class
|
||||
# (self), to the first non-abstract class. Since classes don't know
|
||||
|
|
Loading…
Reference in a new issue