Class: ActiveStorageValidations::ContentTypeValidator

Inherits:
ActiveModel::EachValidator
  • Object
show all
Includes:
ErrorHandler, 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 ErrorHandler

#add_error, #initialize_error_options

Methods included from OptionProcUnfolding

#unfold_procs

Instance Method Details

#authorized_types(record) ⇒ Object



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

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



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

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

#is_valid?(file, types) ⇒ Boolean

Returns:

  • (Boolean)


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

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



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

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

#validate_each(record, attribute, _value) ⇒ Object



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

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 = initialize_error_options(options)
  errors_options[:authorized_types] = types_to_human_format(types)

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

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