Question

I have a class:

class Validator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless valid?(value)
      record.errors.add(attribute, attribute.to_sym, options.merge(value: value))
    end
  end
end

And I have a huge amount of subclasses(with just private valid? method), i.e

class KppValidator < Validator
  private

  def valid?(kpp)
    kpp.size == 9
  end
end

Is there any way to avoid writing private before each valid? method in descendant classes?

I tried to write 'private :valid?', in class Validator, but got an exception no such method 'valid?'

What I can do?

Was it helpful?

Solution

I think your whole approach is a bit odd in the Ruby context. A more Rubyish and Railsy approach would be to write a macro and then use a block in your subclasses rather than a private method.

Something like this:

class Validator < ActiveModel::EachValidator
  def self.validate_using(&block)
    define_method :validate_each do |record, attribute, value|
      unless block[value]
        record.errors.add(attribute, attribute.to_sym, options.merge(value: value))
      end
    end
  end
end

class KppValidator < Validator
  validate_using { |kpp| kpp.size == 9 }
end

Since this defines the whole validate_each method, this even saves you a method call during validation (at the minor expense of a bit of extra work while initializing everything).

I don't know if this is worthwhile for just ten validators, I'll leave that up to you.

OTHER TIPS

Writing private on its own can be inconvenient if you want to shift back to public for subsequent methods. Instead you could try:

class KppValidator < Validator
  def valid?(kpp)
    kpp.size == 9
  end
  private :valid?
end

As of Ruby 2.1.0 def returns the method name as a symbol, so you can streamline this as:

class KppValidator < Validator
  private def valid?(kpp)
    kpp.size == 9
  end
end

But you're right, even if you were to define valid? as a private method in the base class, it will become public in the subclass when you redefine it unless you explicitly make it private.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top