4

I have the following rails/paperclip validator:

class ImageRatioValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    attr_name = "#{attribute}_width".to_sym
    value = record.send(:read_attribute_for_validation, attribute)
    valid_ratios = options[:ratio]

    if !value.queued_for_write[:original].blank?
      geo = Paperclip::Geometry.from_file value.queued_for_write[:original]

      # first we need to validate the ratio
      cur_ratio = nil
      valid_ratios.each do |ratio, max_width|
        parts = ratio.split ":"
        next unless (geo.height * parts.first.to_f) == (geo.width * parts.last.to_f)
        cur_ratio = ratio
      end
      # then we need to make sure the maximum width of the ratio is honoured
      if cur_ratio
        if not valid_ratios[cur_ratio].to_f >= geo.width
          record.errors[attribute] << "The maximum width for ratio #{cur_ratio} is #{valid_ratios[cur_ratio]}. Given width was #{geo.width}!"
        end
      else
        record.errors[attribute] << "Please make sure you upload a stall logo with a valid ratio (#{valid_ratios.keys.join(", ")})!"
      end
    end
  end
end

the validator is used in both super (super-class is not abstract so can be instanciated) and sub-class. In the sub-class I need to change the ratios allowed:

Super-class:

class Superclass
    validates_attachment :logo, :image_ratio => { :ratio  => {"1:1" => "28", "4:1" => "50", "5:1" => "40"} }
end

Sub-class:

class Subclass < Superclass
  validates_attachment :logo, :image_ratio => { :ratio  => {"1:1" => "40", "2:1" => "60"} }
end

The validator works as expected in the super-class however seems to ignore the new ratios given in the sub-class.
Am I trying to use the validators in a non Rails way? How should I be using the validators in a situation like the one described above?

luxerama
  • 1,109
  • 2
  • 14
  • 31

2 Answers2

0

When you inherit from the superclass you also get the validators from it. I'm not 100% sure of this but I think that you just add your new validators to the list of old ones, ie both constrains apply.

I think the easiest solution is to put common logic in a module or inherit from a common superclass. You could also do something like this, but I think it's pretty ugly:

class Superclass
    with_options :unless => Proc.new { |a| a.validators.any? } do |super_validators|
        super_validators.validates :password, :length => { :minimum => 10 }
    end
end
Björn Nilsson
  • 3,703
  • 1
  • 24
  • 29
0

This isn't ideal as a solution, but fairly clean.

Just use custom validation based on the type. This way you will have both validators defined in the super class, but it will definitely work.

class Superclass
    validates_attachment :logo, :image_ratio => { :ratio  => {"1:1" => "28", "4:1" => "50", "5:1" => "40"} }, :if => self.is_a?(SuperClass)
    validates_attachment :logo, :image_ratio => { :ratio  => {"1:1" => "40", "2:1" => "60"} }, :if => self.is_a?(SubClass)
end
vvohra87
  • 5,594
  • 4
  • 22
  • 34