active_storage_validations 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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[