active_storage_validations 1.1.3 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +133 -69
- data/config/locales/da.yml +33 -0
- data/config/locales/de.yml +5 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/es.yml +5 -0
- data/config/locales/fr.yml +5 -0
- data/config/locales/it.yml +5 -0
- data/config/locales/ja.yml +5 -0
- data/config/locales/nl.yml +5 -0
- data/config/locales/pl.yml +5 -0
- data/config/locales/pt-BR.yml +5 -0
- data/config/locales/ru.yml +5 -0
- data/config/locales/sv.yml +10 -1
- data/config/locales/tr.yml +5 -0
- data/config/locales/uk.yml +5 -0
- data/config/locales/vi.yml +5 -0
- data/config/locales/zh-CN.yml +5 -0
- data/lib/active_storage_validations/aspect_ratio_validator.rb +47 -22
- data/lib/active_storage_validations/attached_validator.rb +12 -3
- data/lib/active_storage_validations/base_size_validator.rb +66 -0
- data/lib/active_storage_validations/concerns/errorable.rb +38 -0
- data/lib/active_storage_validations/concerns/symbolizable.rb +8 -6
- data/lib/active_storage_validations/content_type_validator.rb +41 -6
- data/lib/active_storage_validations/dimension_validator.rb +15 -15
- data/lib/active_storage_validations/limit_validator.rb +44 -7
- data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +119 -0
- data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +25 -36
- data/lib/active_storage_validations/matchers/base_size_validator_matcher.rb +134 -0
- data/lib/active_storage_validations/matchers/concerns/active_storageable.rb +17 -0
- data/lib/active_storage_validations/matchers/concerns/allow_blankable.rb +26 -0
- data/lib/active_storage_validations/matchers/concerns/attachable.rb +48 -0
- data/lib/active_storage_validations/matchers/concerns/contextable.rb +47 -0
- data/lib/active_storage_validations/matchers/concerns/messageable.rb +26 -0
- data/lib/active_storage_validations/matchers/concerns/rspecable.rb +25 -0
- data/lib/active_storage_validations/matchers/concerns/validatable.rb +11 -10
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +44 -27
- data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +67 -59
- data/lib/active_storage_validations/matchers/processable_image_validator_matcher.rb +78 -0
- data/lib/active_storage_validations/matchers/size_validator_matcher.rb +8 -126
- data/lib/active_storage_validations/matchers/total_size_validator_matcher.rb +40 -0
- data/lib/active_storage_validations/matchers.rb +3 -0
- data/lib/active_storage_validations/metadata.rb +60 -28
- data/lib/active_storage_validations/processable_image_validator.rb +14 -5
- data/lib/active_storage_validations/size_validator.rb +7 -51
- data/lib/active_storage_validations/total_size_validator.rb +49 -0
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations.rb +3 -2
- metadata +38 -39
- data/lib/active_storage_validations/error_handler.rb +0 -21
@@ -1,56 +1,55 @@
|
|
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'
|
3
8
|
require_relative 'concerns/validatable.rb'
|
4
9
|
|
5
10
|
module ActiveStorageValidations
|
6
11
|
module Matchers
|
7
|
-
def validate_attached_of(
|
8
|
-
AttachedValidatorMatcher.new(
|
12
|
+
def validate_attached_of(attribute_name)
|
13
|
+
AttachedValidatorMatcher.new(attribute_name)
|
9
14
|
end
|
10
15
|
|
11
16
|
class AttachedValidatorMatcher
|
17
|
+
include ActiveStorageable
|
18
|
+
include Attachable
|
19
|
+
include Contextable
|
20
|
+
include Messageable
|
21
|
+
include Rspecable
|
12
22
|
include Validatable
|
13
23
|
|
14
24
|
def initialize(attribute_name)
|
25
|
+
initialize_contextable
|
26
|
+
initialize_messageable
|
27
|
+
initialize_rspecable
|
15
28
|
@attribute_name = attribute_name
|
16
|
-
@custom_message = nil
|
17
29
|
end
|
18
30
|
|
19
31
|
def description
|
20
|
-
"validate
|
32
|
+
"validate that :#{@attribute_name} must be attached"
|
21
33
|
end
|
22
34
|
|
23
|
-
def
|
24
|
-
|
25
|
-
self
|
35
|
+
def failure_message
|
36
|
+
"is expected to validate attachment of :#{@attribute_name}"
|
26
37
|
end
|
27
38
|
|
28
39
|
def matches?(subject)
|
29
40
|
@subject = subject.is_a?(Class) ? subject.new : subject
|
30
|
-
responds_to_methods &&
|
31
|
-
is_valid_when_file_attached? &&
|
32
|
-
is_invalid_when_file_not_attached? &&
|
33
|
-
validate_custom_message?
|
34
|
-
end
|
35
|
-
|
36
|
-
def failure_message
|
37
|
-
"is expected to validate attached of #{@attribute_name}"
|
38
|
-
end
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
+
is_a_valid_active_storage_attribute? &&
|
43
|
+
is_context_valid? &&
|
44
|
+
is_custom_message_valid? &&
|
45
|
+
is_valid_when_file_attached? &&
|
46
|
+
is_invalid_when_file_not_attached?
|
42
47
|
end
|
43
48
|
|
44
49
|
private
|
45
50
|
|
46
|
-
def responds_to_methods
|
47
|
-
@subject.respond_to?(@attribute_name) &&
|
48
|
-
@subject.public_send(@attribute_name).respond_to?(:attach) &&
|
49
|
-
@subject.public_send(@attribute_name).respond_to?(:detach)
|
50
|
-
end
|
51
|
-
|
52
51
|
def is_valid_when_file_attached?
|
53
|
-
|
52
|
+
attach_file unless file_attached?
|
54
53
|
validate
|
55
54
|
is_valid?
|
56
55
|
end
|
@@ -61,7 +60,7 @@ module ActiveStorageValidations
|
|
61
60
|
!is_valid?
|
62
61
|
end
|
63
62
|
|
64
|
-
def
|
63
|
+
def is_custom_message_valid?
|
65
64
|
return true unless @custom_message
|
66
65
|
|
67
66
|
detach_file if file_attached?
|
@@ -69,16 +68,6 @@ module ActiveStorageValidations
|
|
69
68
|
has_an_error_message_which_is_custom_message?
|
70
69
|
end
|
71
70
|
|
72
|
-
def attach_dummy_file
|
73
|
-
dummy_file = {
|
74
|
-
io: Tempfile.new('.'),
|
75
|
-
filename: 'dummy.txt',
|
76
|
-
content_type: 'text/plain'
|
77
|
-
}
|
78
|
-
|
79
|
-
@subject.public_send(@attribute_name).attach(dummy_file)
|
80
|
-
end
|
81
|
-
|
82
71
|
def file_attached?
|
83
72
|
@subject.public_send(@attribute_name).attached?
|
84
73
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Big thank you to the paperclip validation matchers:
|
4
|
+
# https://github.com/thoughtbot/paperclip/blob/v6.1.0/lib/paperclip/matchers/validate_attachment_size_matcher.rb
|
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'
|
13
|
+
|
14
|
+
module ActiveStorageValidations
|
15
|
+
module Matchers
|
16
|
+
class BaseSizeValidatorMatcher
|
17
|
+
# BaseSizeValidatorMatcher is an abstract class and shouldn't be instantiated directly.
|
18
|
+
|
19
|
+
include ActiveStorageable
|
20
|
+
include AllowBlankable
|
21
|
+
include Attachable
|
22
|
+
include Contextable
|
23
|
+
include Messageable
|
24
|
+
include Rspecable
|
25
|
+
include Validatable
|
26
|
+
|
27
|
+
def initialize(attribute_name)
|
28
|
+
initialize_allow_blankable
|
29
|
+
initialize_contextable
|
30
|
+
initialize_messageable
|
31
|
+
initialize_rspecable
|
32
|
+
@attribute_name = attribute_name
|
33
|
+
@min = @max = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def less_than(size)
|
37
|
+
@max = size - 1.byte
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def less_than_or_equal_to(size)
|
42
|
+
@max = size
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def greater_than(size)
|
47
|
+
@min = size + 1.byte
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def greater_than_or_equal_to(size)
|
52
|
+
@min = size
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def between(range)
|
57
|
+
@min, @max = range.first, range.last
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def matches?(subject)
|
62
|
+
@subject = subject.is_a?(Class) ? subject.new : subject
|
63
|
+
|
64
|
+
is_a_valid_active_storage_attribute? &&
|
65
|
+
is_context_valid? &&
|
66
|
+
is_allowing_blank? &&
|
67
|
+
is_custom_message_valid? &&
|
68
|
+
not_lower_than_min? &&
|
69
|
+
higher_than_min? &&
|
70
|
+
lower_than_max? &&
|
71
|
+
not_higher_than_max?
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def build_failure_message(message)
|
77
|
+
return unless @failure_message_artefacts.present?
|
78
|
+
|
79
|
+
message << " but there seem to have issues with the matcher methods you used, since:"
|
80
|
+
@failure_message_artefacts.each do |error_case|
|
81
|
+
message << " validation failed when provided with a #{error_case[:size]} bytes test file"
|
82
|
+
end
|
83
|
+
message << " whereas it should have passed"
|
84
|
+
end
|
85
|
+
|
86
|
+
def not_lower_than_min?
|
87
|
+
@min.nil? || !passes_validation_with_size(@min - 1)
|
88
|
+
end
|
89
|
+
|
90
|
+
def higher_than_min?
|
91
|
+
@min.nil? || passes_validation_with_size(@min + 1)
|
92
|
+
end
|
93
|
+
|
94
|
+
def lower_than_max?
|
95
|
+
@max.nil? || @max == Float::INFINITY || passes_validation_with_size(@max - 1)
|
96
|
+
end
|
97
|
+
|
98
|
+
def not_higher_than_max?
|
99
|
+
@max.nil? || @max == Float::INFINITY || !passes_validation_with_size(@max + 1)
|
100
|
+
end
|
101
|
+
|
102
|
+
def passes_validation_with_size(size)
|
103
|
+
mock_size_for(io, size) do
|
104
|
+
attach_file
|
105
|
+
validate
|
106
|
+
detach_file
|
107
|
+
is_valid? || add_failure_message_artefact(size)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_failure_message_artefact(size)
|
112
|
+
@failure_message_artefacts << { size: size }
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
def is_custom_message_valid?
|
117
|
+
return true unless @custom_message
|
118
|
+
|
119
|
+
mock_size_for(io, -1.kilobytes) do
|
120
|
+
attach_file
|
121
|
+
validate
|
122
|
+
detach_file
|
123
|
+
has_an_error_message_which_is_custom_message?
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def mock_size_for(io, size)
|
128
|
+
Matchers.stub_method(io, :size, size) do
|
129
|
+
yield
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module ActiveStorageValidations
|
4
|
+
module Matchers
|
5
|
+
module ActiveStorageable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def is_a_valid_active_storage_attribute?
|
11
|
+
@subject.respond_to?(@attribute_name) &&
|
12
|
+
@subject.public_send(@attribute_name).respond_to?(:attach) &&
|
13
|
+
@subject.public_send(@attribute_name).respond_to?(:detach)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module ActiveStorageValidations
|
4
|
+
module Matchers
|
5
|
+
module AllowBlankable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def initialize_allow_blankable
|
9
|
+
@allow_blank = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def allow_blank
|
13
|
+
@allow_blank = true
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def is_allowing_blank?
|
20
|
+
return true unless @allow_blank
|
21
|
+
|
22
|
+
validate
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ActiveStorageValidations
|
2
|
+
module Matchers
|
3
|
+
module Attachable
|
4
|
+
private
|
5
|
+
|
6
|
+
def attach_file(file = dummy_file)
|
7
|
+
@subject.public_send(@attribute_name).attach(file)
|
8
|
+
@subject.public_send(@attribute_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def dummy_file
|
12
|
+
{
|
13
|
+
io: io,
|
14
|
+
filename: 'test.png',
|
15
|
+
content_type: 'image/png'
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def processable_image
|
20
|
+
{
|
21
|
+
io: File.open(Rails.root.join('public', 'image_1920x1080.png')),
|
22
|
+
filename: 'image_1920x1080_file.png',
|
23
|
+
content_type: 'image/png'
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def not_processable_image
|
28
|
+
{
|
29
|
+
io: Tempfile.new('.'),
|
30
|
+
filename: 'processable.txt',
|
31
|
+
content_type: 'text/plain'
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def io
|
36
|
+
@io ||= Tempfile.new('Hello world!')
|
37
|
+
end
|
38
|
+
|
39
|
+
def detach_file
|
40
|
+
@subject.attachment_changes.delete(@attribute_name.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
def file_attached?
|
44
|
+
@subject.public_send(@attribute_name).attached?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module ActiveStorageValidations
|
4
|
+
module Matchers
|
5
|
+
module Contextable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def initialize_contextable
|
9
|
+
@context = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def on(context)
|
13
|
+
@context = context
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def is_context_valid?
|
20
|
+
return true if !@context && attribute_validators.none? { |validator| validator.options[:on] }
|
21
|
+
|
22
|
+
raise ArgumentError, "This validator matcher needs the #on option to work since its validator has one" if !@context && attribute_validators.all? { |validator| validator.options[:on] }
|
23
|
+
raise ArgumentError, "This validator matcher option only allows a symbol or an array" if !(@context.is_a?(Symbol) || @context.is_a?(Array))
|
24
|
+
|
25
|
+
if @context.is_a?(Array)
|
26
|
+
(validator_contexts & @context.map(&:to_s)) == validator_contexts || raise_context_not_listed_error
|
27
|
+
elsif @context.is_a?(Symbol)
|
28
|
+
validator_contexts.include?(@context.to_s) || raise_context_not_listed_error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def validator_contexts
|
33
|
+
attribute_validators.map do |validator|
|
34
|
+
case validator.options[:on]
|
35
|
+
when Array then validator.options[:on].map { |context| context.to_s }
|
36
|
+
when NilClass then nil
|
37
|
+
else validator.options[:on].to_s
|
38
|
+
end
|
39
|
+
end.flatten.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def raise_context_not_listed_error
|
43
|
+
raise ArgumentError, "One of the provided contexts to the #on method is not found in any of the listed contexts for this attribute"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module ActiveStorageValidations
|
4
|
+
module Matchers
|
5
|
+
module Messageable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def initialize_messageable
|
9
|
+
@custom_message = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_message(custom_message)
|
13
|
+
@custom_message = custom_message
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def has_an_error_message_which_is_custom_message?
|
20
|
+
validator_errors_for_attribute.one? do |error|
|
21
|
+
error[:error] == @custom_message
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module ActiveStorageValidations
|
4
|
+
module Matchers
|
5
|
+
module Rspecable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def initialize_rspecable
|
9
|
+
@failure_message_artefacts = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
raise NotImplementedError, "#{self.class} did not define #{__method__}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def failure_message
|
17
|
+
raise NotImplementedError, "#{self.class} did not define #{__method__}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def failure_message_when_negated
|
21
|
+
failure_message.sub(/is expected to validate/, 'is expected not to validate')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
require "active_support/concern"
|
3
2
|
|
4
3
|
module ActiveStorageValidations
|
@@ -9,7 +8,7 @@ module ActiveStorageValidations
|
|
9
8
|
private
|
10
9
|
|
11
10
|
def validate
|
12
|
-
@subject.validate
|
11
|
+
@subject.validate(@context)
|
13
12
|
end
|
14
13
|
|
15
14
|
def validator_errors_for_attribute
|
@@ -27,7 +26,7 @@ module ActiveStorageValidations
|
|
27
26
|
def available_errors
|
28
27
|
[
|
29
28
|
*validator_class::ERROR_TYPES,
|
30
|
-
*
|
29
|
+
*errors_from_custom_messages
|
31
30
|
].compact
|
32
31
|
end
|
33
32
|
|
@@ -35,19 +34,21 @@ module ActiveStorageValidations
|
|
35
34
|
self.class.name.gsub(/::Matchers|Matcher/, '').constantize
|
36
35
|
end
|
37
36
|
|
38
|
-
def
|
39
|
-
|
37
|
+
def attribute_validator
|
38
|
+
@subject.class.validators_on(@attribute_name).find do |validator|
|
40
39
|
validator.class == validator_class
|
41
40
|
end
|
42
|
-
|
43
|
-
associated_validation.options[:message]
|
44
41
|
end
|
45
42
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
43
|
+
def attribute_validators
|
44
|
+
@subject.class.validators_on(@attribute_name).select do |validator|
|
45
|
+
validator.class == validator_class
|
49
46
|
end
|
50
47
|
end
|
48
|
+
|
49
|
+
def errors_from_custom_messages
|
50
|
+
attribute_validators.map { |validator| validator.options[:message] }
|
51
|
+
end
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
@@ -3,25 +3,46 @@
|
|
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'
|
6
12
|
require_relative 'concerns/validatable.rb'
|
7
13
|
|
8
14
|
module ActiveStorageValidations
|
9
15
|
module Matchers
|
10
|
-
def validate_content_type_of(
|
11
|
-
ContentTypeValidatorMatcher.new(
|
16
|
+
def validate_content_type_of(attribute_name)
|
17
|
+
ContentTypeValidatorMatcher.new(attribute_name)
|
12
18
|
end
|
13
19
|
|
14
20
|
class ContentTypeValidatorMatcher
|
21
|
+
include ActiveStorageable
|
22
|
+
include AllowBlankable
|
23
|
+
include Attachable
|
24
|
+
include Contextable
|
25
|
+
include Messageable
|
26
|
+
include Rspecable
|
15
27
|
include Validatable
|
16
28
|
|
17
29
|
def initialize(attribute_name)
|
30
|
+
initialize_allow_blankable
|
31
|
+
initialize_contextable
|
32
|
+
initialize_messageable
|
33
|
+
initialize_rspecable
|
18
34
|
@attribute_name = attribute_name
|
19
35
|
@allowed_types = @rejected_types = []
|
20
|
-
@custom_message = nil
|
21
36
|
end
|
22
37
|
|
23
38
|
def description
|
24
|
-
"validate the content types allowed on
|
39
|
+
"validate the content types allowed on :#{@attribute_name}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def failure_message
|
43
|
+
message = ["is expected to validate the content types of :#{@attribute_name}"]
|
44
|
+
build_failure_message(message)
|
45
|
+
message.join("\n")
|
25
46
|
end
|
26
47
|
|
27
48
|
def allowing(*types)
|
@@ -34,42 +55,37 @@ module ActiveStorageValidations
|
|
34
55
|
self
|
35
56
|
end
|
36
57
|
|
37
|
-
def with_message(message)
|
38
|
-
@custom_message = message
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
58
|
def matches?(subject)
|
43
59
|
@subject = subject.is_a?(Class) ? subject.new : subject
|
44
60
|
|
45
|
-
|
61
|
+
is_a_valid_active_storage_attribute? &&
|
62
|
+
is_context_valid? &&
|
63
|
+
is_allowing_blank? &&
|
64
|
+
is_custom_message_valid? &&
|
46
65
|
all_allowed_types_allowed? &&
|
47
|
-
all_rejected_types_rejected?
|
48
|
-
validate_custom_message?
|
66
|
+
all_rejected_types_rejected?
|
49
67
|
end
|
50
68
|
|
51
|
-
|
52
|
-
message = ["Expected #{@attribute_name}"]
|
69
|
+
protected
|
53
70
|
|
71
|
+
def build_failure_message(message)
|
54
72
|
if @allowed_types_not_allowed.present?
|
55
|
-
message << "
|
56
|
-
message << "#{@allowed_types_not_allowed
|
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"
|
57
75
|
end
|
58
76
|
|
59
77
|
if @rejected_types_not_rejected.present?
|
60
|
-
message << "
|
61
|
-
message << "#{@rejected_types_not_rejected
|
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"
|
62
80
|
end
|
63
|
-
|
64
|
-
message.join("\n")
|
65
81
|
end
|
66
82
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
83
|
+
def pluralize(types)
|
84
|
+
if types.count == 1
|
85
|
+
":#{types[0]} was"
|
86
|
+
else
|
87
|
+
":#{types.join(", :")} were"
|
88
|
+
end
|
73
89
|
end
|
74
90
|
|
75
91
|
def all_allowed_types_allowed?
|
@@ -85,6 +101,7 @@ module ActiveStorageValidations
|
|
85
101
|
def type_allowed?(type)
|
86
102
|
attach_file_of_type(type)
|
87
103
|
validate
|
104
|
+
detach_file
|
88
105
|
is_valid?
|
89
106
|
end
|
90
107
|
|
@@ -92,7 +109,7 @@ module ActiveStorageValidations
|
|
92
109
|
@subject.public_send(@attribute_name).attach(attachment_for(type))
|
93
110
|
end
|
94
111
|
|
95
|
-
def
|
112
|
+
def is_custom_message_valid?
|
96
113
|
return true unless @custom_message
|
97
114
|
|
98
115
|
attach_invalid_content_type_file
|