Class: ActiveStorageValidations::DimensionValidator

Inherits:
ActiveModel::EachValidator
  • Object
show all
Includes:
OptionProcUnfolding
Defined in:
lib/active_storage_validations/dimension_validator.rb

Overview

:nodoc

Constant Summary collapse

AVAILABLE_CHECKS =
%i[width height min max].freeze

Instance Method Summary collapse

Methods included from OptionProcUnfolding

#unfold_procs

Instance Method Details

#add_error(record, attribute, default_message, **attrs) ⇒ Object



129
130
131
132
133
# File 'lib/active_storage_validations/dimension_validator.rb', line 129

def add_error(record, attribute, default_message, **attrs)
  message = options[:message].presence || default_message
  return if record.errors.added?(attribute, message)
  record.errors.add(attribute, message, **attrs)
end

#check_validity!Object

Raises:

  • (ArgumentError)


34
35
36
37
# File 'lib/active_storage_validations/dimension_validator.rb', line 34

def check_validity!
  return true if AVAILABLE_CHECKS.any? { |argument| options.key?(argument) }
  raise ArgumentError, 'You must pass either :width, :height, :min or :max to the validator'
end

#is_valid?(record, attribute, file_metadata) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/active_storage_validations/dimension_validator.rb', line 71

def is_valid?(record, attribute, )
  flat_options = process_options(record)
  # Validation fails unless file metadata contains valid width and height.
  if [:width].to_i <= 0 || [:height].to_i <= 0
    add_error(record, attribute, :image_metadata_missing)
    return false
  end

  # Validation based on checks :min and :max (:min, :max has higher priority to :width, :height).
  if flat_options[:min] || flat_options[:max]
    if flat_options[:min] && (
      (flat_options[:width][:min] && [:width] < flat_options[:width][:min]) ||
      (flat_options[:height][:min] && [:height] < flat_options[:height][:min])
      )
      add_error(record, attribute, :dimension_min_inclusion, width: flat_options[:width][:min], height: flat_options[:height][:min])
      return false
    end
    if flat_options[:max] && (
      (flat_options[:width][:max] && [:width] > flat_options[:width][:max]) ||
      (flat_options[:height][:max] && [:height] > flat_options[:height][:max])
      )
      add_error(record, attribute, :dimension_max_inclusion, width: flat_options[:width][:max], height: flat_options[:height][:max])
      return false
    end

  # Validation based on checks :width and :height.
  else
    width_or_height_invalid = false
    [:width, :height].each do |length|
      next unless flat_options[length]
      if flat_options[length].is_a?(Hash)
        if flat_options[length][:in] && ([length] < flat_options[length][:min] || [length] > flat_options[length][:max])
          add_error(record, attribute, :"dimension_#{length}_inclusion", min: flat_options[length][:min], max: flat_options[length][:max])
          width_or_height_invalid = true
        else
          if flat_options[length][:min] && [length] < flat_options[length][:min]
            add_error(record, attribute, :"dimension_#{length}_greater_than_or_equal_to", length: flat_options[length][:min])
            width_or_height_invalid = true
          end
          if flat_options[length][:max] && [length] > flat_options[length][:max]
            add_error(record, attribute, :"dimension_#{length}_less_than_or_equal_to", length: flat_options[length][:max])
            width_or_height_invalid = true
          end
        end
      else
        if [length] != flat_options[length]
          add_error(record, attribute, :"dimension_#{length}_equal_to", length: flat_options[length])
          width_or_height_invalid = true
        end
      end
    end

    return false if width_or_height_invalid
  end

  true # valid file
end

#process_options(record) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/active_storage_validations/dimension_validator.rb', line 11

def process_options(record)
  flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)

  [:width, :height].each do |length|
    if flat_options[length] and flat_options[length].is_a?(Hash)
      if (range = flat_options[length][:in])
        raise ArgumentError, ":in must be a Range" unless range.is_a?(Range)
        flat_options[length][:min], flat_options[length][:max] = range.min, range.max
      end
    end
  end
  [:min, :max].each do |dim|
    if (range = flat_options[dim])
      raise ArgumentError, ":#{dim} must be a Range (width..height)" unless range.is_a?(Range)
      flat_options[:width] = { dim => range.first }
      flat_options[:height] = { dim => range.last }
    end
  end

  flat_options
end

#validate_each(record, attribute, _value) ⇒ Object

Rails 5



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/active_storage_validations/dimension_validator.rb', line 56

def validate_each(record, attribute, _value)
  return true unless record.send(attribute).attached?

  changes = record.attachment_changes[attribute.to_s]
  return true if changes.blank?

  files = Array.wrap(changes.is_a?(ActiveStorage::Attached::Changes::CreateMany) ? changes.attachables : changes.attachable)
  files.each do |file|
     = Metadata.new(file).
    next if is_valid?(record, attribute, )
    break
  end
end