active_storage_validations 1.3.0 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -8
  3. data/config/locales/da.yml +0 -1
  4. data/config/locales/de.yml +0 -1
  5. data/config/locales/en.yml +0 -1
  6. data/config/locales/es.yml +0 -1
  7. data/config/locales/fr.yml +0 -1
  8. data/config/locales/it.yml +0 -1
  9. data/config/locales/ja.yml +0 -1
  10. data/config/locales/nl.yml +0 -1
  11. data/config/locales/pl.yml +0 -1
  12. data/config/locales/pt-BR.yml +0 -1
  13. data/config/locales/ru.yml +0 -1
  14. data/config/locales/sv.yml +0 -1
  15. data/config/locales/tr.yml +0 -1
  16. data/config/locales/uk.yml +0 -1
  17. data/config/locales/vi.yml +0 -1
  18. data/config/locales/zh-CN.yml +0 -1
  19. data/lib/active_storage_validations/aspect_ratio_validator.rb +58 -43
  20. data/lib/active_storage_validations/attached_validator.rb +3 -3
  21. data/lib/active_storage_validations/base_size_validator.rb +5 -4
  22. data/lib/active_storage_validations/content_type_spoof_detector.rb +12 -48
  23. data/lib/active_storage_validations/content_type_validator.rb +97 -49
  24. data/lib/active_storage_validations/dimension_validator.rb +8 -7
  25. data/lib/active_storage_validations/limit_validator.rb +6 -5
  26. data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +7 -7
  27. data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +6 -6
  28. data/lib/active_storage_validations/matchers/base_size_validator_matcher.rb +7 -7
  29. data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +33 -33
  30. data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +7 -7
  31. data/lib/active_storage_validations/matchers/limit_validator_matcher.rb +7 -7
  32. data/lib/active_storage_validations/matchers/processable_image_validator_matcher.rb +7 -7
  33. data/lib/active_storage_validations/metadata.rb +17 -18
  34. data/lib/active_storage_validations/processable_image_validator.rb +5 -5
  35. data/lib/active_storage_validations/shared/attachable.rb +134 -0
  36. data/lib/active_storage_validations/{concerns → shared}/errorable.rb +2 -1
  37. data/lib/active_storage_validations/shared/optionable.rb +27 -0
  38. data/lib/active_storage_validations/size_validator.rb +2 -2
  39. data/lib/active_storage_validations/total_size_validator.rb +2 -2
  40. data/lib/active_storage_validations/version.rb +1 -1
  41. data/lib/active_storage_validations.rb +0 -1
  42. metadata +65 -25
  43. data/lib/active_storage_validations/concerns/metadatable.rb +0 -31
  44. data/lib/active_storage_validations/option_proc_unfolding.rb +0 -16
  45. /data/lib/active_storage_validations/matchers/{concerns → shared}/active_storageable.rb +0 -0
  46. /data/lib/active_storage_validations/matchers/{concerns → shared}/allow_blankable.rb +0 -0
  47. /data/lib/active_storage_validations/matchers/{concerns → shared}/attachable.rb +0 -0
  48. /data/lib/active_storage_validations/matchers/{concerns → shared}/contextable.rb +0 -0
  49. /data/lib/active_storage_validations/matchers/{concerns → shared}/messageable.rb +0 -0
  50. /data/lib/active_storage_validations/matchers/{concerns → shared}/rspecable.rb +0 -0
  51. /data/lib/active_storage_validations/matchers/{concerns → shared}/validatable.rb +0 -0
  52. /data/lib/active_storage_validations/{concerns → shared}/active_storageable.rb +0 -0
  53. /data/lib/active_storage_validations/{concerns → shared}/loggable.rb +0 -0
  54. /data/lib/active_storage_validations/{concerns → shared}/symbolizable.rb +0 -0
@@ -1,15 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/errorable.rb'
5
- require_relative 'concerns/symbolizable.rb'
6
- require_relative 'content_type_spoof_detector.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/attachable'
5
+ require_relative 'shared/errorable'
6
+ require_relative 'shared/optionable'
7
+ require_relative 'shared/symbolizable'
8
+ require_relative 'content_type_spoof_detector'
7
9
 
8
10
  module ActiveStorageValidations
9
11
  class ContentTypeValidator < ActiveModel::EachValidator # :nodoc:
10
12
  include ActiveStorageable
11
- include OptionProcUnfolding
13
+ include Attachable
12
14
  include Errorable
15
+ include Optionable
13
16
  include Symbolizable
14
17
 
15
18
  AVAILABLE_CHECKS = %i[with in].freeze
@@ -26,18 +29,20 @@ module ActiveStorageValidations
26
29
  def validate_each(record, attribute, _value)
27
30
  return if no_attachments?(record, attribute)
28
31
 
29
- types = authorized_types(record)
30
- return if types.empty?
32
+ @authorized_content_types = authorized_content_types_from_options(record)
33
+ return if @authorized_content_types.empty?
31
34
 
32
- attached_files(record, attribute).each do |file|
33
- is_valid?(record, attribute, file, types)
35
+ attachables_from_changes(record, attribute).each do |attachable|
36
+ set_attachable_cached_values(attachable)
37
+ is_valid?(record, attribute, attachable)
34
38
  end
35
39
  end
36
40
 
37
41
  private
38
42
 
39
- def authorized_types(record)
40
- flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
43
+ def authorized_content_types_from_options(record)
44
+ flat_options = set_flat_options(record)
45
+
41
46
  (Array.wrap(flat_options[:with]) + Array.wrap(flat_options[:in])).compact.map do |type|
42
47
  case type
43
48
  when String, Symbol then Marcel::MimeType.for(declared_type: type.to_s, extension: type.to_s)
@@ -46,47 +51,48 @@ module ActiveStorageValidations
46
51
  end
47
52
  end
48
53
 
49
- def types_to_human_format(types)
50
- types
51
- .map { |type| type.is_a?(Regexp) ? type.source : type.to_s.split('/').last.upcase }
52
- .join(', ')
54
+ def set_attachable_cached_values(attachable)
55
+ @attachable_content_type = attachable_content_type(attachable)
56
+ @attachable_filename = attachable_filename(attachable).to_s
53
57
  end
54
58
 
55
- def content_type(file)
56
- # We remove potential mime type parameters
57
- file.blob.present? && file.blob.content_type.downcase.split(/[;,\s]/, 2).first
59
+ def is_valid?(record, attribute, attachable)
60
+ extension_matches_content_type?(record, attribute, attachable) &&
61
+ authorized_content_type?(record, attribute, attachable) &&
62
+ not_spoofing_content_type?(record, attribute, attachable)
58
63
  end
59
64
 
60
- def is_valid?(record, attribute, file, types)
61
- file_type_in_authorized_types?(record, attribute, file, types) &&
62
- not_spoofing_content_type?(record, attribute, file)
65
+ def extension_matches_content_type?(record, attribute, attachable)
66
+ extension = @attachable_filename.split('.').last
67
+
68
+ possible_extensions = Marcel::TYPE_EXTS[@attachable_content_type]
69
+ return true if possible_extensions && extension.in?(possible_extensions)
70
+
71
+ errors_options = initialize_and_populate_error_options(options, attachable)
72
+ add_error(record, attribute, ERROR_TYPES.first, **errors_options)
73
+ false
63
74
  end
64
75
 
65
- def file_type_in_authorized_types?(record, attribute, file, types)
66
- file_type = content_type(file)
67
- file_type_is_authorized = types.any? do |type|
68
- case type
69
- when String then type == file_type
70
- when Regexp then type.match?(file_type.to_s)
76
+ def authorized_content_type?(record, attribute, attachable)
77
+ attachable_content_type_is_authorized = @authorized_content_types.any? do |authorized_content_type|
78
+ case authorized_content_type
79
+ when String then authorized_content_type == marcel_attachable_content_type(attachable)
80
+ when Regexp then authorized_content_type.match?(marcel_attachable_content_type(attachable).to_s)
71
81
  end
72
82
  end
73
83
 
74
- if file_type_is_authorized
75
- true
76
- else
77
- errors_options = initialize_error_options(options, file)
78
- errors_options[:authorized_types] = types_to_human_format(types)
79
- errors_options[:content_type] = content_type(file)
80
- add_error(record, attribute, ERROR_TYPES.first, **errors_options)
81
- false
82
- end
84
+ return true if attachable_content_type_is_authorized
85
+
86
+ errors_options = initialize_and_populate_error_options(options, attachable)
87
+ add_error(record, attribute, ERROR_TYPES.first, **errors_options)
88
+ false
83
89
  end
84
90
 
85
- def not_spoofing_content_type?(record, attribute, file)
91
+ def not_spoofing_content_type?(record, attribute, attachable)
86
92
  return true unless enable_spoofing_protection?
87
93
 
88
- if ContentTypeSpoofDetector.new(record, attribute, file).spoofed?
89
- errors_options = initialize_error_options(options, file)
94
+ if ContentTypeSpoofDetector.new(record, attribute, attachable).spoofed?
95
+ errors_options = initialize_error_options(options, attachable)
90
96
  add_error(record, attribute, ERROR_TYPES.second, **errors_options)
91
97
  false
92
98
  else
@@ -94,6 +100,37 @@ module ActiveStorageValidations
94
100
  end
95
101
  end
96
102
 
103
+ def marcel_attachable_content_type(attachable)
104
+ Marcel::MimeType.for(declared_type: @attachable_content_type, name: @attachable_filename)
105
+ end
106
+
107
+ def enable_spoofing_protection?
108
+ options[:spoofing_protection] == true
109
+ end
110
+
111
+ def initialize_and_populate_error_options(options, attachable)
112
+ errors_options = initialize_error_options(options, attachable)
113
+ errors_options[:content_type] = @attachable_content_type
114
+ errors_options[:human_content_type] = content_type_to_human_format(@attachable_content_type)
115
+ errors_options[:authorized_types] = content_type_to_human_format(@authorized_content_types)
116
+ errors_options
117
+ end
118
+
119
+ def content_type_to_human_format(content_type)
120
+ Array(content_type)
121
+ .map do |content_type|
122
+ case content_type
123
+ when String, Symbol
124
+ content_type.to_s.match?(/\//) ? Marcel::TYPE_EXTS[content_type.to_s]&.first&.upcase : content_type.upcase
125
+ when Regexp
126
+ content_type.source
127
+ end
128
+ end
129
+ .flatten
130
+ .compact
131
+ .join(', ')
132
+ end
133
+
97
134
  def ensure_exactly_one_validator_option
98
135
  unless AVAILABLE_CHECKS.one? { |argument| options.key?(argument) }
99
136
  raise ArgumentError, 'You must pass either :with or :in to the validator'
@@ -104,28 +141,39 @@ module ActiveStorageValidations
104
141
  return true if options[:with]&.is_a?(Proc) || options[:in]&.is_a?(Proc)
105
142
 
106
143
  ([options[:with]] || options[:in]).each do |content_type|
107
- raise ArgumentError, invalid_content_type_message(content_type) if invalid_content_type?(content_type)
144
+ raise ArgumentError, invalid_content_type_option_message(content_type) if invalid_option?(content_type)
108
145
  end
109
146
  end
110
147
 
111
- def invalid_content_type_message(content_type)
112
- <<~ERROR_MESSAGE
113
- You must pass valid content types to the validator
114
- '#{content_type}' is not found in Marcel::EXTENSIONS mimes
115
- ERROR_MESSAGE
148
+ def invalid_content_type_option_message(content_type)
149
+ if content_type.to_s.match?(/\//)
150
+ <<~ERROR_MESSAGE
151
+ You must pass valid content types to the validator
152
+ '#{content_type}' is not found in Marcel::TYPE_EXTS
153
+ ERROR_MESSAGE
154
+ else
155
+ <<~ERROR_MESSAGE
156
+ You must pass valid content types extensions to the validator
157
+ '#{content_type}' is not found in Marcel::EXTENSIONS
158
+ ERROR_MESSAGE
159
+ end
116
160
  end
117
161
 
118
- def invalid_content_type?(content_type)
162
+ def invalid_option?(content_type)
119
163
  case content_type
120
164
  when String, Symbol
121
- Marcel::MimeType.for(declared_type: content_type.to_s, extension: content_type.to_s) == 'application/octet-stream'
165
+ content_type.to_s.match?(/\//) ? invalid_content_type?(content_type) : invalid_extension?(content_type)
122
166
  when Regexp
123
167
  false # We always validate regexes
124
168
  end
125
169
  end
126
170
 
127
- def enable_spoofing_protection?
128
- options[:spoofing_protection] == true
171
+ def invalid_content_type?(content_type)
172
+ Marcel::TYPE_EXTS[content_type.to_s] == nil
173
+ end
174
+
175
+ def invalid_extension?(content_type)
176
+ Marcel::MimeType.for(extension: content_type.to_s) == 'application/octet-stream'
129
177
  end
130
178
  end
131
179
  end
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/errorable.rb'
5
- require_relative 'concerns/metadatable.rb'
6
- require_relative 'concerns/symbolizable.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/attachable'
5
+ require_relative 'shared/errorable'
6
+ require_relative 'shared/optionable'
7
+ require_relative 'shared/symbolizable'
7
8
 
8
9
  module ActiveStorageValidations
9
10
  class DimensionValidator < ActiveModel::EachValidator # :nodoc
10
11
  include ActiveStorageable
12
+ include Attachable
11
13
  include Errorable
12
- include OptionProcUnfolding
13
- include Metadatable
14
+ include Optionable
14
15
  include Symbolizable
15
16
 
16
17
  AVAILABLE_CHECKS = %i[width height min max].freeze
@@ -122,7 +123,7 @@ module ActiveStorageValidations
122
123
  end
123
124
 
124
125
  def process_options(record)
125
- flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
126
+ flat_options = set_flat_options(record)
126
127
 
127
128
  [:width, :height].each do |length|
128
129
  if flat_options[length] and flat_options[length].is_a?(Hash)
@@ -1,14 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/errorable.rb'
5
- require_relative 'concerns/symbolizable.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/errorable'
5
+ require_relative 'shared/optionable'
6
+ require_relative 'shared/symbolizable'
6
7
 
7
8
  module ActiveStorageValidations
8
9
  class LimitValidator < ActiveModel::EachValidator # :nodoc:
9
10
  include ActiveStorageable
10
- include OptionProcUnfolding
11
11
  include Errorable
12
+ include Optionable
12
13
  include Symbolizable
13
14
 
14
15
  AVAILABLE_CHECKS = %i[max min].freeze
@@ -23,7 +24,7 @@ module ActiveStorageValidations
23
24
 
24
25
  def validate_each(record, attribute, _value)
25
26
  files = attached_files(record, attribute).reject(&:blank?)
26
- flat_options = unfold_procs(record, self.options, AVAILABLE_CHECKS)
27
+ flat_options = set_flat_options(record)
27
28
 
28
29
  return if files_count_valid?(files.count, flat_options)
29
30
 
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/allow_blankable.rb'
5
- require_relative 'concerns/attachable.rb'
6
- require_relative 'concerns/contextable.rb'
7
- require_relative 'concerns/messageable.rb'
8
- require_relative 'concerns/rspecable.rb'
9
- require_relative 'concerns/validatable.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/allow_blankable'
5
+ require_relative 'shared/attachable'
6
+ require_relative 'shared/contextable'
7
+ require_relative 'shared/messageable'
8
+ require_relative 'shared/rspecable'
9
+ require_relative 'shared/validatable'
10
10
 
11
11
  module ActiveStorageValidations
12
12
  module Matchers
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/attachable.rb'
5
- require_relative 'concerns/contextable.rb'
6
- require_relative 'concerns/messageable.rb'
7
- require_relative 'concerns/rspecable.rb'
8
- require_relative 'concerns/validatable.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/attachable'
5
+ require_relative 'shared/contextable'
6
+ require_relative 'shared/messageable'
7
+ require_relative 'shared/rspecable'
8
+ require_relative 'shared/validatable'
9
9
 
10
10
  module ActiveStorageValidations
11
11
  module Matchers
@@ -3,13 +3,13 @@
3
3
  # Big thank you to the paperclip validation matchers:
4
4
  # https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_size_matcher.rb
5
5
 
6
- require_relative 'concerns/active_storageable.rb'
7
- require_relative 'concerns/allow_blankable.rb'
8
- require_relative 'concerns/attachable.rb'
9
- require_relative 'concerns/contextable.rb'
10
- require_relative 'concerns/messageable.rb'
11
- require_relative 'concerns/rspecable.rb'
12
- require_relative 'concerns/validatable.rb'
6
+ require_relative 'shared/active_storageable'
7
+ require_relative 'shared/allow_blankable'
8
+ require_relative 'shared/attachable'
9
+ require_relative 'shared/contextable'
10
+ require_relative 'shared/messageable'
11
+ require_relative 'shared/rspecable'
12
+ require_relative 'shared/validatable'
13
13
 
14
14
  module ActiveStorageValidations
15
15
  module Matchers
@@ -3,13 +3,13 @@
3
3
  # Big thank you to the paperclip validation matchers:
4
4
  # https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
5
5
 
6
- require_relative 'concerns/active_storageable.rb'
7
- require_relative 'concerns/allow_blankable.rb'
8
- require_relative 'concerns/attachable.rb'
9
- require_relative 'concerns/contextable.rb'
10
- require_relative 'concerns/messageable.rb'
11
- require_relative 'concerns/rspecable.rb'
12
- require_relative 'concerns/validatable.rb'
6
+ require_relative 'shared/active_storageable'
7
+ require_relative 'shared/allow_blankable'
8
+ require_relative 'shared/attachable'
9
+ require_relative 'shared/contextable'
10
+ require_relative 'shared/messageable'
11
+ require_relative 'shared/rspecable'
12
+ require_relative 'shared/validatable'
13
13
 
14
14
  module ActiveStorageValidations
15
15
  module Matchers
@@ -32,7 +32,7 @@ module ActiveStorageValidations
32
32
  initialize_messageable
33
33
  initialize_rspecable
34
34
  @attribute_name = attribute_name
35
- @allowed_types = @rejected_types = []
35
+ @allowed_content_types = @rejected_content_types = []
36
36
  end
37
37
 
38
38
  def description
@@ -45,13 +45,13 @@ module ActiveStorageValidations
45
45
  message.join("\n")
46
46
  end
47
47
 
48
- def allowing(*types)
49
- @allowed_types = types.flatten
48
+ def allowing(*content_types)
49
+ @allowed_content_types = content_types.flatten
50
50
  self
51
51
  end
52
52
 
53
- def rejecting(*types)
54
- @rejected_types = types.flatten
53
+ def rejecting(*content_types)
54
+ @rejected_content_types = content_types.flatten
55
55
  self
56
56
  end
57
57
 
@@ -62,21 +62,21 @@ module ActiveStorageValidations
62
62
  is_context_valid? &&
63
63
  is_allowing_blank? &&
64
64
  is_custom_message_valid? &&
65
- all_allowed_types_allowed? &&
66
- all_rejected_types_rejected?
65
+ all_allowed_content_types_allowed? &&
66
+ all_rejected_content_types_rejected?
67
67
  end
68
68
 
69
69
  protected
70
70
 
71
71
  def build_failure_message(message)
72
- if @allowed_types_not_allowed.present?
73
- message << " the following content type#{'s' if @allowed_types.count > 1} should be allowed: :#{@allowed_types.join(", :")}"
74
- message << " but #{pluralize(@allowed_types_not_allowed)} rejected"
72
+ if @allowed_content_types_not_allowed.present?
73
+ message << " the following content type#{'s' if @allowed_content_types.count > 1} should be allowed: :#{@allowed_content_types.join(", :")}"
74
+ message << " but #{pluralize(@allowed_content_types_not_allowed)} rejected"
75
75
  end
76
76
 
77
- if @rejected_types_not_rejected.present?
78
- message << " the following content type#{'s' if @rejected_types.count > 1} should be rejected: :#{@rejected_types.join(", :")}"
79
- message << " but #{pluralize(@rejected_types_not_rejected)} accepted"
77
+ if @rejected_content_types_not_rejected.present?
78
+ message << " the following content type#{'s' if @rejected_content_types.count > 1} should be rejected: :#{@rejected_content_types.join(", :")}"
79
+ message << " but #{pluralize(@rejected_content_types_not_rejected)} accepted"
80
80
  end
81
81
  end
82
82
 
@@ -88,25 +88,25 @@ module ActiveStorageValidations
88
88
  end
89
89
  end
90
90
 
91
- def all_allowed_types_allowed?
92
- @allowed_types_not_allowed ||= @allowed_types.reject { |type| type_allowed?(type) }
93
- @allowed_types_not_allowed.empty?
91
+ def all_allowed_content_types_allowed?
92
+ @allowed_content_types_not_allowed ||= @allowed_content_types.reject { |type| type_allowed?(type) }
93
+ @allowed_content_types_not_allowed.empty?
94
94
  end
95
95
 
96
- def all_rejected_types_rejected?
97
- @rejected_types_not_rejected ||= @rejected_types.select { |type| type_allowed?(type) }
98
- @rejected_types_not_rejected.empty?
96
+ def all_rejected_content_types_rejected?
97
+ @rejected_content_types_not_rejected ||= @rejected_content_types.select { |type| type_allowed?(type) }
98
+ @rejected_content_types_not_rejected.empty?
99
99
  end
100
100
 
101
- def type_allowed?(type)
102
- attach_file_of_type(type)
101
+ def type_allowed?(content_type)
102
+ attach_file_with_content_type(content_type)
103
103
  validate
104
104
  detach_file
105
105
  is_valid?
106
106
  end
107
107
 
108
- def attach_file_of_type(type)
109
- @subject.public_send(@attribute_name).attach(attachment_for(type))
108
+ def attach_file_with_content_type(content_type)
109
+ @subject.public_send(@attribute_name).attach(attachment_for(content_type))
110
110
  end
111
111
 
112
112
  def is_custom_message_valid?
@@ -121,13 +121,13 @@ module ActiveStorageValidations
121
121
  @subject.public_send(@attribute_name).attach(attachment_for('fake/fake'))
122
122
  end
123
123
 
124
- def attachment_for(type)
125
- suffix = type.to_s.split('/').last
124
+ def attachment_for(content_type)
125
+ suffix = Marcel::TYPE_EXTS[content_type.to_s]&.first || 'fake'
126
126
 
127
127
  {
128
128
  io: Tempfile.new('.'),
129
129
  filename: "test.#{suffix}",
130
- content_type: type
130
+ content_type: content_type
131
131
  }
132
132
  end
133
133
 
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/allow_blankable.rb'
5
- require_relative 'concerns/attachable'
6
- require_relative 'concerns/contextable.rb'
7
- require_relative 'concerns/messageable.rb'
8
- require_relative 'concerns/rspecable.rb'
9
- require_relative 'concerns/validatable.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/allow_blankable'
5
+ require_relative 'shared/attachable'
6
+ require_relative 'shared/contextable'
7
+ require_relative 'shared/messageable'
8
+ require_relative 'shared/rspecable'
9
+ require_relative 'shared/validatable'
10
10
 
11
11
  module ActiveStorageValidations
12
12
  module Matchers
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable'
4
- require_relative 'concerns/allow_blankable'
5
- require_relative 'concerns/attachable'
6
- require_relative 'concerns/contextable'
7
- require_relative 'concerns/messageable'
8
- require_relative 'concerns/rspecable'
9
- require_relative 'concerns/validatable'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/allow_blankable'
5
+ require_relative 'shared/attachable'
6
+ require_relative 'shared/contextable'
7
+ require_relative 'shared/messageable'
8
+ require_relative 'shared/rspecable'
9
+ require_relative 'shared/validatable'
10
10
 
11
11
  module ActiveStorageValidations
12
12
  module Matchers
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/allow_blankable.rb'
5
- require_relative 'concerns/attachable.rb'
6
- require_relative 'concerns/contextable.rb'
7
- require_relative 'concerns/messageable.rb'
8
- require_relative 'concerns/rspecable.rb'
9
- require_relative 'concerns/validatable.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/allow_blankable'
5
+ require_relative 'shared/attachable'
6
+ require_relative 'shared/contextable'
7
+ require_relative 'shared/messageable'
8
+ require_relative 'shared/rspecable'
9
+ require_relative 'shared/validatable'
10
10
 
11
11
  module ActiveStorageValidations
12
12
  module Matchers
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/loggable'
3
+ require_relative 'shared/loggable'
4
4
 
5
5
  module ActiveStorageValidations
6
6
  class Metadata
@@ -8,13 +8,13 @@ module ActiveStorageValidations
8
8
 
9
9
  class InvalidImageError < StandardError; end
10
10
 
11
- attr_reader :file
11
+ attr_reader :attachable
12
12
 
13
13
  DEFAULT_IMAGE_PROCESSOR = :mini_magick.freeze
14
14
 
15
- def initialize(file)
15
+ def initialize(attachable)
16
16
  require_image_processor
17
- @file = file
17
+ @attachable = attachable
18
18
  end
19
19
 
20
20
  def valid?
@@ -64,14 +64,9 @@ module ActiveStorageValidations
64
64
  end
65
65
 
66
66
  def read_image
67
- is_string = file.is_a?(String)
68
- if is_string || file.is_a?(ActiveStorage::Blob)
69
- blob =
70
- if is_string
71
- ActiveStorage::Blob.find_signed!(file)
72
- else
73
- file
74
- end
67
+ is_string = attachable.is_a?(String)
68
+ if is_string || attachable.is_a?(ActiveStorage::Blob)
69
+ blob = is_string ? ActiveStorage::Blob.find_signed!(attachable) : attachable
75
70
 
76
71
  tempfile = Tempfile.new(["ActiveStorage-#{blob.id}-", blob.filename.extension_with_delimiter])
77
72
  tempfile.binmode
@@ -107,9 +102,9 @@ module ActiveStorageValidations
107
102
  begin
108
103
  Vips::Image.new_from_file(path)
109
104
  rescue exception_class
110
- # We handle cases where an error is raised when reading the file
105
+ # We handle cases where an error is raised when reading the attachable
111
106
  # because Vips can throw errors rather than returning false
112
- # We stumble upon this issue while reading 0 byte size file
107
+ # We stumble upon this issue while reading 0 byte size attachable
113
108
  # https://github.com/janko/image_processing/issues/97
114
109
  false
115
110
  end
@@ -156,13 +151,13 @@ module ActiveStorageValidations
156
151
  end
157
152
 
158
153
  def read_file_path
159
- case file
154
+ case attachable
160
155
  when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile
161
- file.path
156
+ attachable.path
162
157
  when Hash
163
- io = file.fetch(:io)
158
+ io = attachable.fetch(:io)
164
159
  if io.is_a?(StringIO)
165
- tempfile = Tempfile.new([File.basename(file[:filename], '.*'), File.extname(file[:filename])])
160
+ tempfile = Tempfile.new([File.basename(attachable[:filename], '.*'), File.extname(attachable[:filename])])
166
161
  tempfile.binmode
167
162
  IO.copy_stream(io, tempfile)
168
163
  io.rewind
@@ -172,6 +167,10 @@ module ActiveStorageValidations
172
167
  else
173
168
  File.open(io).path
174
169
  end
170
+ when File
171
+ attachable.path
172
+ when Pathname
173
+ attachable.to_s
175
174
  else
176
175
  raise "Something wrong with params."
177
176
  end
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'concerns/active_storageable.rb'
4
- require_relative 'concerns/errorable.rb'
5
- require_relative 'concerns/metadatable.rb'
6
- require_relative 'concerns/symbolizable.rb'
3
+ require_relative 'shared/active_storageable'
4
+ require_relative 'shared/attachable'
5
+ require_relative 'shared/errorable'
6
+ require_relative 'shared/symbolizable'
7
7
 
8
8
  module ActiveStorageValidations
9
9
  class ProcessableImageValidator < ActiveModel::EachValidator # :nodoc
10
10
  include ActiveStorageable
11
+ include Attachable
11
12
  include Errorable
12
- include Metadatable
13
13
  include Symbolizable
14
14
 
15
15
  ERROR_TYPES = %i[