Class: ActiveStorageValidations::ContentTypeValidator
- Inherits:
-
ActiveModel::EachValidator
- Object
- ActiveModel::EachValidator
- ActiveStorageValidations::ContentTypeValidator
show all
- Includes:
- Errorable, OptionProcUnfolding, Symbolizable
- Defined in:
- lib/active_storage_validations/content_type_validator.rb
Overview
Constant Summary
collapse
- AVAILABLE_CHECKS =
%i[with in].freeze
- ERROR_TYPES =
%i[content_type_invalid].freeze
Instance Method Summary
collapse
Methods included from Errorable
#add_error, #initialize_error_options
#unfold_procs
Instance Method Details
#authorized_types(record) ⇒ Object
39
40
41
42
43
44
45
46
47
48
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 39
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
|
#check_validity! ⇒ Object
15
16
17
18
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 15
def check_validity!
ensure_exactly_one_validator_option
ensure_content_types_validity
end
|
#content_type(file) ⇒ Object
56
57
58
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 56
def content_type(file)
file.blob.present? && file.blob.content_type
end
|
#ensure_content_types_validity ⇒ Object
73
74
75
76
77
78
79
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 73
def ensure_content_types_validity
return true if options[:with]&.is_a?(Proc) || options[:in]&.is_a?(Proc)
([options[:with]] || options[:in]).each do |content_type|
raise ArgumentError, invalid_content_type_message(content_type) if invalid_content_type?(content_type)
end
end
|
#ensure_exactly_one_validator_option ⇒ Object
67
68
69
70
71
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 67
def ensure_exactly_one_validator_option
unless AVAILABLE_CHECKS.one? { |argument| options.key?(argument) }
raise ArgumentError, 'You must pass either :with or :in to the validator'
end
end
|
#invalid_content_type?(content_type) ⇒ Boolean
88
89
90
91
92
93
94
95
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 88
def invalid_content_type?(content_type)
case content_type
when String, Symbol
Marcel::MimeType.for(declared_type: content_type.to_s, extension: content_type.to_s) == 'application/octet-stream'
when Regexp
false end
end
|
#invalid_content_type_message(content_type) ⇒ Object
81
82
83
84
85
86
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 81
def invalid_content_type_message(content_type)
<<~ERROR_MESSAGE
You must pass valid content types to the validator
'#{content_type}' is not find in Marcel::EXTENSIONS mimes
ERROR_MESSAGE
end
|
#is_valid?(file, types) ⇒ Boolean
60
61
62
63
64
65
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 60
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
|
50
51
52
53
54
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 50
def types_to_human_format(types)
types
.map { |type| type.is_a?(Regexp) ? type.source : type.to_s.split('/').last.upcase }
.join(', ')
end
|
#validate_each(record, attribute, _value) ⇒ Object
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
# File 'lib/active_storage_validations/content_type_validator.rb', line 20
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))
files.each do |file|
next if is_valid?(file, types)
errors_options = initialize_error_options(options, file)
errors_options[:authorized_types] = types_to_human_format(types)
errors_options[:content_type] = content_type(file)
add_error(record, attribute, ERROR_TYPES.first, **errors_options)
break
end
end
|