Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove explicit respond_to? and Validator#setup call #10716

Conversation

apotonick
Copy link
Contributor

This moves the setup process of validators into the constructor, pushing all knowledge about this into the validator class itself. Makes it easier to override internals in subclassed validators.

…. instead, respective validators take care of their setup.
@rafaelfranca
Copy link
Member

Could you give us example of what you want to accomplish with this change?

Maybe an example how was the validator subclass before and after it.

@apotonick
Copy link
Contributor Author

This is the "bottom line" of my PR: apotonick@543c59d#L2L88

I could get my stuff working using the existing code. However, my main intend is to remove the respond_to? call and move stuff into Validator itself. While this simplifies the Validator interface it is also preparing some more changes I'd like to push (especially simplifying UniquenessValidator in AR).

Are you worried about the change? Is it because the options contain a :class now (I don't like it either)? It shouldn't break existing code?!

@@ -123,6 +125,10 @@ def kind
def validate(record)
raise NotImplementedError, "Subclasses must implement a validate(record) method."
end

private
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the same indentation of the def.

@rafaelfranca
Copy link
Member

Are you worried about the change?

No. I just want to know more about the motivation of this pull request.

Is it because the options contain a :class now (I don't like it either)?

It is awkward, but it is fine to me.

It shouldn't break existing code?!

I'm not sure of this. setup(klass) is a public method and documented as part of the API (see Validator documentation). We can't just remove it.

@apotonick
Copy link
Contributor Author

You're right! #setup! should be made private soon and called by a public #setup which will be deprecated.

def setup(*)
  deprecation_warning
  setup!
end

private
def setup!
end

@rafaelfranca
Copy link
Member

👍

@apotonick
Copy link
Contributor Author

What is the prefered way of deprecating (and testing this)? Sorry to ask :-)

@rafaelfranca
Copy link
Member

Maybe:

if validator.respond_to?(:setup)
  ActiveSupport::Deprecation.warn 'The `setup` instance method is deprecated and will be removed on Rails 4.2. Define `setup!` without arguments instead.'
  validator.setup(self)
end

You can even provide a code snippet in the deprecation message to make explicit what the users have to do:

Change your setup method to:

class MyValidator < ActiveModel::Validator
  private

  def setup!
    @klass.send :attr_accessor, :custom_attribute
  end
end

To test you can define a Validator class with the setup method defined and assert the deprecation message with the assert_deprecated method when calling validates_with. Something like this:

def test_setup_is_deprecated
  assert_deprecated do
    Class.new do
      include ActiveModel::Validations

      validates_with MyDeprecatedValidator
    end
  end
end

@apotonick
Copy link
Contributor Author

Now the last quest: Why is options.freeze called in Validator#initialize?

@rafaelfranca I wanted to say I really appreciate your responsiveness - amazing! 😸

@@ -107,7 +105,9 @@ def self.kind

# Accepts options that will be made available through the +options+ reader.
def initialize(options = {})
@options = options.freeze
@klass = options[:class]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the need for always storing the @klass if we only need it in some validators and temporarily.

@josevalim
Copy link
Contributor

I have added some comments, :+1 for getting rid of the respond_to? in general.

@apotonick
Copy link
Contributor Author

Cool! I removed the automatic setup! call, I personally like that better. Ready for merge!

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. Change your `setup` method to something like:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@apotonick should not the deprecation warning be updated to show the initialize override example?

@rafaelfranca
Copy link
Member

I like it too. Just a minor comment on the deprecation message.

@rafaelfranca
Copy link
Member

Since it is a user facing change we will need a CHANGELOG entry, and make sure your commits are squashed.

@apotonick
Copy link
Contributor Author

Dunno how to change a PR to another branch, here it goes: https://github.com/apotonick/rails/tree/deprecate-validator-setup rebased to current rails/rails:master and including updated exception and CHANGELOG entry.

@rafaelfranca
Copy link
Member

@apotonick merged.

Thank you for contributing.

@apotonick
Copy link
Contributor Author

Thank you @josevalim and especially @rafaelfranca for that quick and uncomplicated feedback and processing! ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants