Class: ActiveStorageValidations::ContentTypeValidator

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

Overview

:nodoc:

Constant Summary collapse

AVAILABLE_CHECKS =
%i[with in].freeze

Instance Method Summary collapse

Methods included from OptionProcUnfolding

#unfold_procs

Instance Method Details

#authorized_types(record) ⇒ Object



29
30
31
32
33
34
35
36
37
38
# File 'lib/active_storage_validations/content_type_validator.rb', line 29

def authorized_types(record)
  flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
  (Array.wrap(flat_options[:with]) + Array.wrap(flat_options[:in])).compact.map do |type|
    if type.is_a?(Regexp)
      type
    else
      Marcel::MimeType.for(declared_type: type.to_s, extension: type.to_s)
    end
  end
end

#content_type(file) ⇒ Object



46
47
48
# File 'lib/active_storage_validations/content_type_validator.rb', line 46

def content_type(file)
  file.blob.present? && file.blob.content_type
end

#is_valid?(file, types) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
53
54
55
# File 'lib/active_storage_validations/content_type_validator.rb', line 50

def is_valid?(file, types)
  file_type = content_type(file)
  types.any? do |type|
    type == file_type || (type.is_a?(Regexp) && type.match?(file_type.to_s))
  end
end

#types_to_human_format(types) ⇒ Object



40
41
42
43
44
# File 'lib/active_storage_validations/content_type_validator.rb', line 40

def types_to_human_format(types)
  types
    .map { |type| type.to_s.split('/').last.upcase }
    .join(', ')
end

#validate_each(record, attribute, _value) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/active_storage_validations/content_type_validator.rb', line 9

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

  types = authorized_types(record)
  return true if types.empty?
  
  files = Array.wrap(record.send(attribute))

  errors_options = { authorized_types: types_to_human_format(types) }
  errors_options[:message] = options[:message] if options[:message].present?

  files.each do |file|
    next if is_valid?(file, types)

    errors_options[:content_type] = content_type(file)
    record.errors.add(attribute, :content_type_invalid, **errors_options)
    break
  end
end