file_validators 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/README.md +52 -49
- data/lib/file_validators.rb +3 -0
- data/lib/file_validators/locale/en.yml +12 -0
- data/lib/file_validators/validators/file_content_type_validator.rb +22 -22
- data/lib/file_validators/validators/file_size_validator.rb +34 -28
- data/lib/file_validators/version.rb +1 -1
- data/spec/integration/file_content_type_validation_integration_spec.rb +51 -0
- data/spec/integration/file_size_validator_integration_spec.rb +90 -33
- data/spec/lib/file_validators/validators/file_content_type_validator_spec.rb +30 -0
- data/spec/lib/file_validators/validators/file_size_validator_spec.rb +111 -23
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8e04639d14acd35e4d98938b786d372f5218bdd
|
4
|
+
data.tar.gz: b045b75d86de521365bece751da3b3c24ea890c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a57497456ee76a9f96f1d74e3e5599e43d8d9e68ab120c0bd6b8fe6945a643cc04acb7b97c50ec65f33b34c1352a346bf6564f0c695b67940e10a459b2f5be19
|
7
|
+
data.tar.gz: 4fd2174b5f6a7dae46f0f6ada517f4cb918279286918425948c845dd67d0a744f4e6086eb68ee4b2add6da9849c3a0d2033efa8559e664cdc11c828161dbe9c4
|
data/README.md
CHANGED
@@ -47,40 +47,26 @@ end
|
|
47
47
|
|
48
48
|
### File Size Validator:
|
49
49
|
|
50
|
-
* `in`: A range of bytes
|
50
|
+
* `in`: A range of bytes or a proc that returns a range
|
51
51
|
```ruby
|
52
52
|
validates :avatar, file_size: { in: 100.kilobytes..1.megabyte }
|
53
53
|
```
|
54
|
-
* `
|
55
|
-
```ruby
|
56
|
-
validates :avatar, file_size: { less_than_or_equal_to: 50.bytes }
|
57
|
-
```
|
58
|
-
* `greater_than_or_equal_to`: Greater than or equal to a number in bytes
|
59
|
-
```ruby
|
60
|
-
validates :avatar, file_size: { greater_than_or_equal_to: 50.bytes }
|
61
|
-
```
|
62
|
-
* `less_than`: Less than a number in bytes
|
54
|
+
* `less_than`: Less than a number in bytes or a proc that returns a number
|
63
55
|
```ruby
|
64
56
|
validates :avatar, file_size: { less_than: 2.gigabytes }
|
65
57
|
```
|
66
|
-
* `
|
58
|
+
* `less_than_or_equal_to`: Less than or equal to a number in bytes or a proc that returns a number
|
67
59
|
```ruby
|
68
|
-
validates :avatar, file_size: {
|
69
|
-
```
|
70
|
-
You can also combine these options.
|
71
|
-
```ruby
|
72
|
-
validates :avatar, file_size: { less_than: 1.megabyte,
|
73
|
-
greater_than_or_equal_to: 20.kilobytes }
|
60
|
+
validates :avatar, file_size: { less_than_or_equal_to: 50.bytes }
|
74
61
|
```
|
75
|
-
|
62
|
+
* `greater_than`: greater than a number in bytes or a proc that returns a number
|
76
63
|
```ruby
|
77
|
-
validates :avatar, file_size: {
|
78
|
-
less_than_or_equal_to: 3.megabytes }
|
64
|
+
validates :avatar, file_size: { greater_than: 1.byte }
|
79
65
|
```
|
66
|
+
* `greater_than_or_equal_to`: Greater than or equal to a number in bytes or a proc that returns a number
|
80
67
|
```ruby
|
81
|
-
validates :avatar, file_size: {
|
68
|
+
validates :avatar, file_size: { greater_than_or_equal_to: 50.bytes }
|
82
69
|
```
|
83
|
-
If you use `:in`, then the other options will be neglected.
|
84
70
|
* `message`: Error message to display. With all the options above except `:in`, you will get `count` as a replacement.
|
85
71
|
With `:in` you will get `min` and `max` as replacements.
|
86
72
|
`count`, `min` and `max` each will have its value and unit together.
|
@@ -96,55 +82,53 @@ validates :document, file_size: { in: 1.kilobyte..1.megabyte,
|
|
96
82
|
* `if`: A lambda or name of an instance method. Validation will only be run if this lambda or method returns true.
|
97
83
|
* `unless`: Same as `if` but validates if lambda or method returns false.
|
98
84
|
|
99
|
-
|
100
|
-
|
101
|
-
* `allow`: Allowed content types. Can be a single content type or an array. Each type can be a String or a Regexp. Allows all by default.
|
85
|
+
You can combine different options.
|
102
86
|
```ruby
|
103
|
-
|
104
|
-
|
105
|
-
```
|
106
|
-
```ruby
|
107
|
-
# array of strings
|
108
|
-
validates :attachment, file_content_type: { allow: ['image/jpeg', 'image/png', 'text/plain'] }
|
87
|
+
validates :avatar, file_size: { less_than: 1.megabyte,
|
88
|
+
greater_than_or_equal_to: 20.kilobytes }
|
109
89
|
```
|
90
|
+
The following two examples are equivalent:
|
110
91
|
```ruby
|
111
|
-
|
112
|
-
|
92
|
+
validates :avatar, file_size: { greater_than_or_equal_to: 500.kilobytes,
|
93
|
+
less_than_or_equal_to: 3.megabytes }
|
113
94
|
```
|
114
95
|
```ruby
|
115
|
-
|
116
|
-
validates :attachment, file_content_type: { allow: [/^image\/.*/, /^text\/.*/] }
|
96
|
+
validates :avatar, file_size: { in: 500.kilobytes..3.megabytes }
|
117
97
|
```
|
98
|
+
Options can also take `Proc`/`lambda`:
|
99
|
+
|
118
100
|
```ruby
|
119
|
-
|
120
|
-
validates :attachment, file_content_type: { allow: [/^image\/.*/, 'video/mp4'] }
|
101
|
+
validates :avatar, file_size: { less_than: lambda { |record| record.size_in_bytes } }
|
121
102
|
```
|
122
|
-
|
103
|
+
|
104
|
+
### File Content Type Validator
|
105
|
+
|
106
|
+
* `allow`: Allowed content types. Can be a single content type or an array. Each type can be a String or a Regexp. It also accepts proc. Allows all by default.
|
123
107
|
```ruby
|
124
108
|
# string
|
125
|
-
validates :avatar, file_content_type: {
|
109
|
+
validates :avatar, file_content_type: { allow: 'image/jpeg' }
|
126
110
|
```
|
127
111
|
```ruby
|
128
112
|
# array of strings
|
129
|
-
validates :attachment, file_content_type: {
|
113
|
+
validates :attachment, file_content_type: { allow: ['image/jpeg', 'image/png', 'text/plain'] }
|
130
114
|
```
|
131
115
|
```ruby
|
132
116
|
# regexp
|
133
|
-
validates :avatar, file_content_type: {
|
117
|
+
validates :avatar, file_content_type: { allow: /^image\/.*/ }
|
134
118
|
```
|
135
119
|
```ruby
|
136
120
|
# array of regexps
|
137
|
-
validates :attachment, file_content_type: {
|
121
|
+
validates :attachment, file_content_type: { allow: [/^image\/.*/, /^text\/.*/] }
|
138
122
|
```
|
139
123
|
```ruby
|
140
124
|
# array of regexps and strings
|
141
|
-
validates :attachment, file_content_type: {
|
125
|
+
validates :attachment, file_content_type: { allow: [/^image\/.*/, 'video/mp4'] }
|
142
126
|
```
|
143
|
-
You can also combine `:allow` and `:exclude`:
|
144
127
|
```ruby
|
145
|
-
#
|
146
|
-
validates :
|
128
|
+
# proc/lambda example
|
129
|
+
validates :video, file_content_type: { allow: lambda { |record| record.content_types } }
|
147
130
|
```
|
131
|
+
* `exclude`: Forbidden content types. Can be a single content type or an array. Each type can be a String or a Regexp. It also accepts `proc`. See `:allow` options examples.
|
148
132
|
* `message`: The message to display when the uploaded file has an invalid content type.
|
149
133
|
You will get `types` as a replacement. You can write error messages without using any replacement.
|
150
134
|
```ruby
|
@@ -158,16 +142,35 @@ validates :avatar, file_content_type: { allow: ['image/jpeg', 'image/gif'],
|
|
158
142
|
* `if`: A lambda or name of an instance method. Validation will only be run is this lambda or method returns true.
|
159
143
|
* `unless`: Same as `if` but validates if lambda or method returns false.
|
160
144
|
|
145
|
+
You can combine `:allow` and `:exclude`:
|
146
|
+
```ruby
|
147
|
+
# this will allow all the image types except png and gif
|
148
|
+
validates :avatar, file_content_type: { allow: /^image\/.*/, exclude: ['image/png', 'image/gif'] }
|
149
|
+
```
|
150
|
+
|
161
151
|
## i18n Translations
|
162
152
|
|
163
|
-
|
153
|
+
File Size Errors
|
154
|
+
* `file_size_is_in`: takes `min` and `max` as replacements
|
155
|
+
* `file_size_is_less_than`: takes `count` as replacement
|
156
|
+
* `file_size_is_less_than_or_equal_to`: takes `count` as replacement
|
157
|
+
* `file_size_is_greater_than`: takes `count` as replacement
|
158
|
+
* `file_size_is_greater_than_or_equal_to`: takes `count` as replacement
|
159
|
+
|
160
|
+
Content Type Errors
|
161
|
+
* `allowed_file_content_types`: generated when you have specified allowed types but the content type
|
162
|
+
of the file doesn't match. takes `types` as replacement.
|
163
|
+
* `excluded_file_content_types`: generated when you have specified excluded types and the content type
|
164
|
+
of the file matches anyone of them. takes `types` as replacement.
|
164
165
|
|
165
|
-
|
166
|
+
This gem provides `en` translations for this errors under `errors.messages` namespace.
|
167
|
+
If you want to override and/or create other locales, you can
|
168
|
+
check [this](https://github.com/musaffa/file_validators/blob/master/lib/file_validators/locale/en.yml) out to see how translations are done.
|
166
169
|
|
167
170
|
You can override all of them with the `:message` option.
|
168
171
|
|
169
172
|
For unit format, it will use `number.human.storage_units.format` from your locale.
|
170
|
-
For unit translation,
|
173
|
+
For unit translation, `number.human.storage_units` is used.
|
171
174
|
Rails applications already have these translations either in ActiveSupport's locale (Rails 4) or in ActionView's locale (Rails 3).
|
172
175
|
In case your setup doesn't have the translations, here's an example for `en`:
|
173
176
|
|
data/lib/file_validators.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
1
|
require 'active_model'
|
2
2
|
require 'file_validators/validators/file_size_validator'
|
3
3
|
require 'file_validators/validators/file_content_type_validator'
|
4
|
+
|
5
|
+
locale_path = Dir.glob(File.dirname(__FILE__) + '/file_validators/locale/*.yml')
|
6
|
+
I18n.load_path += locale_path unless I18n.load_path.include?(locale_path)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
en:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
file_size_is_in: ! 'file size must be between %{min} and %{max}'
|
5
|
+
file_size_is_less_than: ! 'file size must be less than %{count}'
|
6
|
+
file_size_is_less_than_or_equal_to: ! 'file size must be less than or equal to %{count}'
|
7
|
+
file_size_is_greater_than: ! 'file size must be greater than %{count}'
|
8
|
+
file_size_is_greater_than_or_equal_to: ! 'file size must be greater than or equal to %{count}'
|
9
|
+
|
10
|
+
allowed_file_content_types: ! 'file should be one of %{types}'
|
11
|
+
excluded_file_content_types: ! 'file cannot be %{types}'
|
12
|
+
|
@@ -1,10 +1,8 @@
|
|
1
1
|
module ActiveModel
|
2
2
|
module Validations
|
3
3
|
|
4
|
-
class FileContentTypeValidator <
|
5
|
-
|
6
|
-
super
|
7
|
-
end
|
4
|
+
class FileContentTypeValidator < EachValidator
|
5
|
+
CHECKS = [:allow, :exclude].freeze
|
8
6
|
|
9
7
|
def self.helper_method_name
|
10
8
|
:validates_file_content_type
|
@@ -18,34 +16,36 @@ module ActiveModel
|
|
18
16
|
end
|
19
17
|
end
|
20
18
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
19
|
+
def check_validity!
|
20
|
+
unless (CHECKS & options.keys).present?
|
21
|
+
raise ArgumentError, 'You must at least pass in :allow or :exclude option'
|
24
22
|
end
|
25
|
-
end
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
options.slice(*CHECKS).each do |option, value|
|
25
|
+
unless value.is_a?(String) || value.is_a?(Array) || value.is_a?(Regexp) || value.is_a?(Proc)
|
26
|
+
raise ArgumentError, ":#{option} must be a string, an array, a regex or a proc"
|
27
|
+
end
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
33
|
-
|
34
|
-
record.errors.add attribute, :invalid, options.merge(:types => types.join(', '))
|
35
|
-
end
|
31
|
+
private
|
36
32
|
|
37
|
-
def
|
38
|
-
[
|
33
|
+
def validate_whitelist(record, attribute, value)
|
34
|
+
allowed_types = [options_call(record, :allow)].flatten.compact
|
35
|
+
if allowed_types.present? && allowed_types.none? { |type| type === value }
|
36
|
+
record.errors.add attribute, :allowed_file_content_types, options.merge(:types => allowed_types.join(', '))
|
37
|
+
end
|
39
38
|
end
|
40
39
|
|
41
|
-
def
|
42
|
-
[
|
40
|
+
def validate_blacklist(record, attribute, value)
|
41
|
+
forbidden_types = [options_call(record, :exclude)].flatten.compact
|
42
|
+
if forbidden_types.present? && forbidden_types.any? { |type| type === value }
|
43
|
+
record.errors.add attribute, :excluded_file_content_types, options.merge(:types => forbidden_types.join(', '))
|
44
|
+
end
|
43
45
|
end
|
44
46
|
|
45
|
-
def
|
46
|
-
|
47
|
-
raise ArgumentError, 'You must pass in either :allow or :exclude to the validator'
|
48
|
-
end
|
47
|
+
def options_call(record, key)
|
48
|
+
options[key].is_a?(Proc) ? options[key].call(record) : options[key]
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module ActiveModel
|
2
2
|
module Validations
|
3
3
|
|
4
|
-
class FileSizeValidator <
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
4
|
+
class FileSizeValidator < EachValidator
|
5
|
+
CHECKS = { in: :===,
|
6
|
+
less_than: :<,
|
7
|
+
less_than_or_equal_to: :<=,
|
8
|
+
greater_than: :>,
|
9
|
+
greater_than_or_equal_to: :>= }.freeze
|
11
10
|
|
12
11
|
def self.helper_method_name
|
13
12
|
:validates_file_size
|
@@ -15,44 +14,51 @@ module ActiveModel
|
|
15
14
|
|
16
15
|
def validate_each(record, attribute, value)
|
17
16
|
unless value.blank?
|
18
|
-
options.slice(*
|
19
|
-
|
20
|
-
|
21
|
-
record.errors.add(attribute,
|
17
|
+
options.slice(*CHECKS.keys).each do |option, option_value|
|
18
|
+
option_value = option_value.call(record) if option_value.is_a?(Proc)
|
19
|
+
unless valid_size?(value.size, option, option_value)
|
20
|
+
record.errors.add(attribute,
|
21
|
+
"file_size_is_#{option}".to_sym,
|
22
|
+
filtered_options(value).merge!(detect_error_options(option_value)))
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
28
|
def check_validity!
|
28
|
-
unless (
|
29
|
-
raise ArgumentError, '
|
29
|
+
unless (CHECKS.keys & options.keys).present?
|
30
|
+
raise ArgumentError, 'You must at least pass in one of these options - :in, :less_than,
|
31
|
+
:less_than_or_equal_to, :greater_than and :greater_than_or_equal_to'
|
32
|
+
end
|
33
|
+
|
34
|
+
options.slice(*CHECKS.keys).each do |option, value|
|
35
|
+
unless value.is_a?(Numeric) || value.is_a?(Range) || value.is_a?(Proc)
|
36
|
+
raise ArgumentError, ":#{option} must be a number, a range or a proc"
|
37
|
+
end
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
33
41
|
private
|
34
42
|
|
35
|
-
def
|
36
|
-
if
|
37
|
-
|
38
|
-
|
39
|
-
|
43
|
+
def valid_size?(size, option, option_value)
|
44
|
+
if option_value.is_a?(Range)
|
45
|
+
option_value.send(CHECKS[option], size)
|
46
|
+
else
|
47
|
+
size.send(CHECKS[option], option_value)
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
def filtered_options(value)
|
52
|
+
filtered = options.except(*CHECKS.keys)
|
53
|
+
filtered[:value] = value
|
54
|
+
filtered
|
47
55
|
end
|
48
56
|
|
49
|
-
def detect_error_options(
|
50
|
-
if
|
51
|
-
|
52
|
-
min = options[:greater_than_or_equal_to]
|
53
|
-
error_options = { min: human_size(min), max: human_size(max) }
|
57
|
+
def detect_error_options(option_value)
|
58
|
+
if option_value.is_a?(Range)
|
59
|
+
{ min: human_size(option_value.min), max: human_size(option_value.max) }
|
54
60
|
else
|
55
|
-
|
61
|
+
{ count: human_size(option_value) }
|
56
62
|
end
|
57
63
|
end
|
58
64
|
|
@@ -91,6 +91,34 @@ describe 'File Content Type integration with ActiveModel' do
|
|
91
91
|
it { is_expected.not_to be_valid }
|
92
92
|
end
|
93
93
|
end
|
94
|
+
|
95
|
+
context 'as a proc' do
|
96
|
+
before :all do
|
97
|
+
Person.class_eval do
|
98
|
+
Person.reset_callbacks(:validate)
|
99
|
+
validates :avatar, file_content_type: { allow: lambda { |record| ['image/jpeg', 'text/plain'] } }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
subject { Person.new }
|
104
|
+
|
105
|
+
context 'with allowed types' do
|
106
|
+
it 'validates jpeg' do
|
107
|
+
subject.avatar = Rack::Test::UploadedFile.new(@cute_path, 'image/jpeg')
|
108
|
+
expect(subject).to be_valid
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'validates text file' do
|
112
|
+
subject.avatar = Rack::Test::UploadedFile.new(@sample_text_path, 'text/plain')
|
113
|
+
expect(subject).to be_valid
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'with a disallowed type' do
|
118
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_cute_path, 'image/png') }
|
119
|
+
it { is_expected.not_to be_valid }
|
120
|
+
end
|
121
|
+
end
|
94
122
|
end
|
95
123
|
|
96
124
|
context ':exclude option' do
|
@@ -170,6 +198,29 @@ describe 'File Content Type integration with ActiveModel' do
|
|
170
198
|
end
|
171
199
|
end
|
172
200
|
end
|
201
|
+
|
202
|
+
context 'as a proc' do
|
203
|
+
before :all do
|
204
|
+
Person.class_eval do
|
205
|
+
Person.reset_callbacks(:validate)
|
206
|
+
validates :avatar, file_content_type: { exclude: lambda { |record| /^image\/.*/ } }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
subject { Person.new }
|
211
|
+
|
212
|
+
context 'with an allowed type' do
|
213
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@sample_text_path, 'text/plain') }
|
214
|
+
it { is_expected.to be_valid }
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'with a disallowed types' do
|
218
|
+
it 'invalidates jpeg image file' do
|
219
|
+
subject.avatar = Rack::Test::UploadedFile.new(@cute_path, 'image/jpeg')
|
220
|
+
expect(subject).not_to be_valid
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
173
224
|
end
|
174
225
|
|
175
226
|
context ':allow and :exclude combined' do
|
@@ -14,55 +14,112 @@ describe 'File Size Validator integration with ActiveModel' do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
context ':in option' do
|
17
|
-
|
18
|
-
|
19
|
-
Person.
|
20
|
-
|
17
|
+
context 'as a range' do
|
18
|
+
before :all do
|
19
|
+
Person.class_eval do
|
20
|
+
Person.reset_callbacks(:validate)
|
21
|
+
validates :avatar, file_size: { in: 20.kilobytes..40.kilobytes }
|
22
|
+
end
|
21
23
|
end
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
+
subject { Person.new }
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
context 'when file size is out of range' do
|
28
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@cute_path) }
|
29
|
+
it { is_expected.not_to be_valid }
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
context 'when file size is out of range' do
|
33
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_cute_path) }
|
34
|
+
it { is_expected.not_to be_valid }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when file size within range' do
|
38
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_bubble_path) }
|
39
|
+
it { is_expected.to be_valid }
|
40
|
+
end
|
34
41
|
end
|
35
42
|
|
36
|
-
context '
|
37
|
-
before
|
38
|
-
|
43
|
+
context 'as a proc' do
|
44
|
+
before :all do
|
45
|
+
Person.class_eval do
|
46
|
+
Person.reset_callbacks(:validate)
|
47
|
+
validates :avatar, file_size: { in: lambda { |record| 20.kilobytes..40.kilobytes } }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
subject { Person.new }
|
52
|
+
|
53
|
+
context 'when file size is out of range' do
|
54
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@cute_path) }
|
55
|
+
it { is_expected.not_to be_valid }
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when file size is out of range' do
|
59
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_cute_path) }
|
60
|
+
it { is_expected.not_to be_valid }
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when file size within range' do
|
64
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_bubble_path) }
|
65
|
+
it { is_expected.to be_valid }
|
66
|
+
end
|
39
67
|
end
|
40
68
|
end
|
41
69
|
|
42
70
|
context ':greater_than and :less_than option' do
|
43
|
-
|
44
|
-
|
45
|
-
Person.
|
46
|
-
|
47
|
-
|
71
|
+
context 'as numbers' do
|
72
|
+
before :all do
|
73
|
+
Person.class_eval do
|
74
|
+
Person.reset_callbacks(:validate)
|
75
|
+
validates :avatar, file_size: { greater_than: 20.kilobytes,
|
76
|
+
less_than: 40.kilobytes }
|
77
|
+
end
|
48
78
|
end
|
49
|
-
end
|
50
79
|
|
51
|
-
|
80
|
+
subject { Person.new }
|
52
81
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
82
|
+
context 'when file size is out of range' do
|
83
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@cute_path) }
|
84
|
+
it { is_expected.not_to be_valid }
|
85
|
+
end
|
57
86
|
|
58
|
-
|
59
|
-
|
60
|
-
|
87
|
+
context 'when file size is out of range' do
|
88
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_cute_path) }
|
89
|
+
it { is_expected.not_to be_valid }
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when file size within range' do
|
93
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_bubble_path) }
|
94
|
+
it { is_expected.to be_valid }
|
95
|
+
end
|
61
96
|
end
|
62
97
|
|
63
|
-
context '
|
64
|
-
before
|
65
|
-
|
98
|
+
context 'as procs' do
|
99
|
+
before :all do
|
100
|
+
Person.class_eval do
|
101
|
+
Person.reset_callbacks(:validate)
|
102
|
+
validates :avatar, file_size: { greater_than: lambda { |record| 20.kilobytes },
|
103
|
+
less_than: lambda { |record| 40.kilobytes } }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
subject { Person.new }
|
108
|
+
|
109
|
+
context 'when file size is out of range' do
|
110
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@cute_path) }
|
111
|
+
it { is_expected.not_to be_valid }
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when file size is out of range' do
|
115
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_cute_path) }
|
116
|
+
it { is_expected.not_to be_valid }
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when file size within range' do
|
120
|
+
before { subject.avatar = Rack::Test::UploadedFile.new(@chubby_bubble_path) }
|
121
|
+
it { is_expected.to be_valid }
|
122
|
+
end
|
66
123
|
end
|
67
124
|
end
|
68
125
|
|
@@ -28,6 +28,11 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
28
28
|
before { build_validator allow: ['image/png', 'image/jpg', 'image/jpeg'] }
|
29
29
|
it { is_expected.to allow_file_content_type('image/png', @validator) }
|
30
30
|
end
|
31
|
+
|
32
|
+
context 'as a proc' do
|
33
|
+
before { build_validator allow: lambda { |record| ['image/png', 'image/jpg', 'image/jpeg'] } }
|
34
|
+
it { is_expected.to allow_file_content_type('image/png', @validator) }
|
35
|
+
end
|
31
36
|
end
|
32
37
|
|
33
38
|
context 'with a disallowed type' do
|
@@ -40,6 +45,11 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
40
45
|
before { build_validator allow: /^text\/.*/ }
|
41
46
|
it { is_expected.not_to allow_file_content_type('image/png', @validator) }
|
42
47
|
end
|
48
|
+
|
49
|
+
context 'as a proc' do
|
50
|
+
before { build_validator allow: lambda { |record| /^text\/.*/ } }
|
51
|
+
it { is_expected.not_to allow_file_content_type('image/png', @validator) }
|
52
|
+
end
|
43
53
|
|
44
54
|
context 'with :message option' do
|
45
55
|
context 'without interpolation' do
|
@@ -55,6 +65,11 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
55
65
|
message: 'Avatar should have content type image/png') }
|
56
66
|
end
|
57
67
|
end
|
68
|
+
|
69
|
+
context 'default message' do
|
70
|
+
before { build_validator allow: 'image/png' }
|
71
|
+
it { is_expected.not_to allow_file_content_type('image/jpeg', @validator, message: 'Avatar file should be one of image/png') }
|
72
|
+
end
|
58
73
|
end
|
59
74
|
end
|
60
75
|
|
@@ -74,6 +89,11 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
74
89
|
before { build_validator exclude: ['image/png', 'image/jpg', 'image/jpeg'] }
|
75
90
|
it { is_expected.to allow_file_content_type('image/gif', @validator) }
|
76
91
|
end
|
92
|
+
|
93
|
+
context 'as a proc' do
|
94
|
+
before { build_validator exclude: lambda { |record| ['image/png', 'image/jpg', 'image/jpeg'] } }
|
95
|
+
it { is_expected.to allow_file_content_type('image/gif', @validator) }
|
96
|
+
end
|
77
97
|
end
|
78
98
|
|
79
99
|
context 'with a disallowed type' do
|
@@ -86,6 +106,11 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
86
106
|
before { build_validator exclude: /^text\/.*/ }
|
87
107
|
it { is_expected.not_to allow_file_content_type('text/plain', @validator) }
|
88
108
|
end
|
109
|
+
|
110
|
+
context 'as an proc' do
|
111
|
+
before { build_validator exclude: lambda { |record| /^text\/.*/ } }
|
112
|
+
it { is_expected.not_to allow_file_content_type('text/plain', @validator) }
|
113
|
+
end
|
89
114
|
|
90
115
|
context 'with :message option' do
|
91
116
|
context 'without interpolation' do
|
@@ -101,6 +126,11 @@ describe ActiveModel::Validations::FileContentTypeValidator do
|
|
101
126
|
message: 'Avatar should not have content type image/jpeg') }
|
102
127
|
end
|
103
128
|
end
|
129
|
+
|
130
|
+
context 'default message' do
|
131
|
+
before { build_validator exclude: 'image/png' }
|
132
|
+
it { is_expected.not_to allow_file_content_type('image/png', @validator, message: 'Avatar file cannot be image/png') }
|
133
|
+
end
|
104
134
|
end
|
105
135
|
end
|
106
136
|
|
@@ -25,49 +25,108 @@ describe ActiveModel::Validations::FileSizeValidator do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
context 'with :in option' do
|
28
|
-
|
28
|
+
context 'as a range' do
|
29
|
+
before { build_validator in: (5.kilobytes..10.kilobytes) }
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
it { is_expected.to allow_file_size(7.kilobytes, @validator) }
|
32
|
+
it { is_expected.not_to allow_file_size(4.kilobytes, @validator) }
|
33
|
+
it { is_expected.not_to allow_file_size(11.kilobytes, @validator) }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'as a proc' do
|
37
|
+
before { build_validator in: lambda { |record| (5.kilobytes..10.kilobytes) } }
|
38
|
+
|
39
|
+
it { is_expected.to allow_file_size(7.kilobytes, @validator) }
|
40
|
+
it { is_expected.not_to allow_file_size(4.kilobytes, @validator) }
|
41
|
+
it { is_expected.not_to allow_file_size(11.kilobytes, @validator) }
|
42
|
+
end
|
33
43
|
end
|
34
44
|
|
35
45
|
context 'with :greater_than_or_equal_to option' do
|
36
|
-
|
46
|
+
context 'as a number' do
|
47
|
+
before { build_validator greater_than_or_equal_to: 10.kilobytes }
|
37
48
|
|
38
|
-
|
39
|
-
|
40
|
-
|
49
|
+
it { is_expected.to allow_file_size(11.kilobytes, @validator) }
|
50
|
+
it { is_expected.to allow_file_size(10.kilobytes, @validator) }
|
51
|
+
it { is_expected.not_to allow_file_size(9.kilobytes, @validator) }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'as a proc' do
|
55
|
+
before { build_validator greater_than_or_equal_to: lambda { |record| 10.kilobytes } }
|
56
|
+
|
57
|
+
it { is_expected.to allow_file_size(11.kilobytes, @validator) }
|
58
|
+
it { is_expected.to allow_file_size(10.kilobytes, @validator) }
|
59
|
+
it { is_expected.not_to allow_file_size(9.kilobytes, @validator) }
|
60
|
+
end
|
41
61
|
end
|
42
62
|
|
43
63
|
context 'with :less_than_or_equal_to option' do
|
44
|
-
|
64
|
+
context 'as a number' do
|
65
|
+
before { build_validator less_than_or_equal_to: 10.kilobytes }
|
45
66
|
|
46
|
-
|
47
|
-
|
48
|
-
|
67
|
+
it { is_expected.to allow_file_size(9.kilobytes, @validator) }
|
68
|
+
it { is_expected.to allow_file_size(10.kilobytes, @validator) }
|
69
|
+
it { is_expected.not_to allow_file_size(11.kilobytes, @validator) }
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'as a proc' do
|
73
|
+
before { build_validator less_than_or_equal_to: lambda { |record| 10.kilobytes } }
|
74
|
+
|
75
|
+
it { is_expected.to allow_file_size(9.kilobytes, @validator) }
|
76
|
+
it { is_expected.to allow_file_size(10.kilobytes, @validator) }
|
77
|
+
it { is_expected.not_to allow_file_size(11.kilobytes, @validator) }
|
78
|
+
end
|
49
79
|
end
|
50
80
|
|
51
81
|
context 'with :greater_than option' do
|
52
|
-
|
82
|
+
context 'as a number' do
|
83
|
+
before { build_validator greater_than: 10.kilobytes }
|
84
|
+
|
85
|
+
it { is_expected.to allow_file_size(11.kilobytes, @validator) }
|
86
|
+
it { is_expected.not_to allow_file_size(10.kilobytes, @validator) }
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'as a proc' do
|
90
|
+
before { build_validator greater_than: lambda { |record| 10.kilobytes } }
|
53
91
|
|
54
|
-
|
55
|
-
|
92
|
+
it { is_expected.to allow_file_size(11.kilobytes, @validator) }
|
93
|
+
it { is_expected.not_to allow_file_size(10.kilobytes, @validator) }
|
94
|
+
end
|
56
95
|
end
|
57
96
|
|
58
97
|
context 'with :less_than option' do
|
59
|
-
|
98
|
+
context 'as a number' do
|
99
|
+
before { build_validator less_than: 10.kilobytes }
|
100
|
+
|
101
|
+
it { is_expected.to allow_file_size(9.kilobytes, @validator) }
|
102
|
+
it { is_expected.not_to allow_file_size(10.kilobytes, @validator) }
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'as a proc' do
|
106
|
+
before { build_validator less_than: lambda { |record| 10.kilobytes } }
|
60
107
|
|
61
|
-
|
62
|
-
|
108
|
+
it { is_expected.to allow_file_size(9.kilobytes, @validator) }
|
109
|
+
it { is_expected.not_to allow_file_size(10.kilobytes, @validator) }
|
110
|
+
end
|
63
111
|
end
|
64
112
|
|
65
113
|
context 'with :greater_than and :less_than option' do
|
66
|
-
|
114
|
+
context 'as a number' do
|
115
|
+
before { build_validator greater_than: 5.kilobytes, less_than: 10.kilobytes }
|
116
|
+
|
117
|
+
it { is_expected.to allow_file_size(7.kilobytes, @validator) }
|
118
|
+
it { is_expected.not_to allow_file_size(5.kilobytes, @validator) }
|
119
|
+
it { is_expected.not_to allow_file_size(10.kilobytes, @validator) }
|
120
|
+
end
|
67
121
|
|
68
|
-
|
69
|
-
|
70
|
-
|
122
|
+
context 'as a proc' do
|
123
|
+
before { build_validator greater_than: lambda { |record| 5.kilobytes },
|
124
|
+
less_than: lambda { |record| 10.kilobytes } }
|
125
|
+
|
126
|
+
it { is_expected.to allow_file_size(7.kilobytes, @validator) }
|
127
|
+
it { is_expected.not_to allow_file_size(5.kilobytes, @validator) }
|
128
|
+
it { is_expected.not_to allow_file_size(10.kilobytes, @validator) }
|
129
|
+
end
|
71
130
|
end
|
72
131
|
|
73
132
|
context 'with :message option' do
|
@@ -81,6 +140,35 @@ describe ActiveModel::Validations::FileSizeValidator do
|
|
81
140
|
message: "Avatar is invalid. (Between #{@storage_units[5120]} and #{@storage_units[10240]} please.)") }
|
82
141
|
end
|
83
142
|
|
143
|
+
context 'default error message' do
|
144
|
+
context 'given :in options' do
|
145
|
+
before { build_validator in: 5.kilobytes..10.kilobytes }
|
146
|
+
|
147
|
+
it { is_expected.not_to allow_file_size(11.kilobytes, @validator,
|
148
|
+
message: "Avatar file size must be between #{@storage_units[5120]} and #{@storage_units[10240]}") }
|
149
|
+
it { is_expected.not_to allow_file_size(4.kilobytes, @validator,
|
150
|
+
message: "Avatar file size must be between #{@storage_units[5120]} and #{@storage_units[10240]}") }
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'given :greater_than and :less_than options' do
|
154
|
+
before { build_validator greater_than: 5.kilobytes, less_than: 10.kilobytes }
|
155
|
+
|
156
|
+
it { is_expected.not_to allow_file_size(11.kilobytes, @validator,
|
157
|
+
message: "Avatar file size must be less than #{@storage_units[10240]}") }
|
158
|
+
it { is_expected.not_to allow_file_size(4.kilobytes, @validator,
|
159
|
+
message: "Avatar file size must be greater than #{@storage_units[5120]}") }
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'given :greater_than_or_equal_to and :less_than_or_equal_to options' do
|
163
|
+
before { build_validator greater_than_or_equal_to: 5.kilobytes, less_than_or_equal_to: 10.kilobytes }
|
164
|
+
|
165
|
+
it { is_expected.not_to allow_file_size(11.kilobytes, @validator,
|
166
|
+
message: "Avatar file size must be less than or equal to #{@storage_units[10240]}") }
|
167
|
+
it { is_expected.not_to allow_file_size(4.kilobytes, @validator,
|
168
|
+
message: "Avatar file size must be greater than or equal to #{@storage_units[5120]}") }
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
84
172
|
|
85
173
|
context 'using the helper' do
|
86
174
|
before { Dummy.validates_file_size :avatar, in: (5.kilobytes..10.kilobytes) }
|
@@ -95,7 +183,7 @@ describe ActiveModel::Validations::FileSizeValidator do
|
|
95
183
|
expect { build_validator message: 'Some message' }.to raise_error(ArgumentError)
|
96
184
|
end
|
97
185
|
|
98
|
-
(ActiveModel::Validations::FileSizeValidator::
|
186
|
+
(ActiveModel::Validations::FileSizeValidator::CHECKS.keys).each do |argument|
|
99
187
|
it "does not raise argument error if #{argument} was given" do
|
100
188
|
expect { build_validator argument => 5.kilobytes }.not_to raise_error
|
101
189
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: file_validators
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ahmad Musaffa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- gemfiles/activemodel_4.0.gemfile
|
103
103
|
- gemfiles/activemodel_4.1.gemfile
|
104
104
|
- lib/file_validators.rb
|
105
|
+
- lib/file_validators/locale/en.yml
|
105
106
|
- lib/file_validators/validators/file_content_type_validator.rb
|
106
107
|
- lib/file_validators/validators/file_size_validator.rb
|
107
108
|
- lib/file_validators/version.rb
|
@@ -156,4 +157,3 @@ test_files:
|
|
156
157
|
- spec/spec_helper.rb
|
157
158
|
- spec/support/matchers/allow_content_type.rb
|
158
159
|
- spec/support/matchers/allow_file_size.rb
|
159
|
-
has_rdoc:
|