active_storage_validations 1.0.0 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/config/locales/en.yml +1 -0
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +12 -34
- data/lib/active_storage_validations/metadata.rb +18 -7
- data/lib/active_storage_validations/option_proc_unfolding.rb +2 -2
- data/lib/active_storage_validations/processable_image_validator.rb +43 -0
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7b0998dd3938eee42be49dc3d831eaea8482001a0e03227f61cc0330050a3a1
|
4
|
+
data.tar.gz: 72a82d3965c026f118bd1d4bc7e0338a2313c43394f780577cbbe944356caf39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0117ebfeed615802b45e4f341eea6e5676d8189e4a4bf81faa565e8e49f418142a7aa3466a6cd3f92761e029ff54f58298259ae390682649d5ad5950e52d787
|
7
|
+
data.tar.gz: e6ab73fe085110abe6b346e3eb837a59ca81b499707cdbf8df9773647feefd7b11ca4e5be03329226954a43756a5ceda9550169ff5402a6f275cfc7b4865f6b9
|
data/README.md
CHANGED
@@ -19,6 +19,7 @@ This gems doing it for you. Just use `attached: true` or `content_type: 'image/p
|
|
19
19
|
* validates dimension of images/videos
|
20
20
|
* validates number of uploaded files (min/max required)
|
21
21
|
* validates aspect ratio (if square, portrait, landscape, is_16_9, ...)
|
22
|
+
* validates if file can be processed by MiniMagick or Vips
|
22
23
|
* custom error messages
|
23
24
|
* allow procs for dynamic determination of values
|
24
25
|
|
@@ -40,6 +41,7 @@ class User < ApplicationRecord
|
|
40
41
|
dimension: { width: { min: 800, max: 2400 },
|
41
42
|
height: { min: 600, max: 1800 }, message: 'is not given between dimension' }
|
42
43
|
validates :image, attached: true,
|
44
|
+
processable_image: true,
|
43
45
|
content_type: ['image/png', 'image/jpeg'],
|
44
46
|
aspect_ratio: :landscape
|
45
47
|
end
|
@@ -164,6 +166,7 @@ en:
|
|
164
166
|
aspect_ratio_not_landscape: "must be a landscape image"
|
165
167
|
aspect_ratio_is_not: "must have an aspect ratio of %{aspect_ratio}"
|
166
168
|
aspect_ratio_unknown: "has an unknown aspect ratio"
|
169
|
+
image_not_processable: "is not a valid image"
|
167
170
|
```
|
168
171
|
|
169
172
|
In some cases, Active Storage Validations provides variables to help you customize messages:
|
@@ -311,9 +314,9 @@ end
|
|
311
314
|
|
312
315
|
To run tests in root folder of gem:
|
313
316
|
|
314
|
-
* `BUNDLE_GEMFILE=gemfiles/rails_5_2.gemfile bundle exec rake test` to run for Rails 5.2
|
315
317
|
* `BUNDLE_GEMFILE=gemfiles/rails_6_0.gemfile bundle exec rake test` to run for Rails 6.0
|
316
318
|
* `BUNDLE_GEMFILE=gemfiles/rails_6_1.gemfile bundle exec rake test` to run for Rails 6.1
|
319
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle exec rake test` to run for Rails 7.0
|
317
320
|
* `BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake test` to run for Rails main branch
|
318
321
|
|
319
322
|
Snippet to run in console:
|
@@ -395,6 +398,8 @@ You are welcome to contribute.
|
|
395
398
|
= https://github.com/gr8bit
|
396
399
|
= https://github.com/codegeek319
|
397
400
|
= https://github.com/clwy-cn
|
401
|
+
= https://github.com/kukicola
|
402
|
+
= https://github.com/sobrinho
|
398
403
|
|
399
404
|
## License
|
400
405
|
|
data/config/locales/en.yml
CHANGED
@@ -33,15 +33,19 @@ module ActiveStorageValidations
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def failure_message
|
36
|
-
|
37
|
-
Expected #{@attribute_name}
|
36
|
+
message = ["Expected #{@attribute_name}"]
|
38
37
|
|
39
|
-
|
40
|
-
|
38
|
+
if @allowed_types
|
39
|
+
message << "Accept content types: #{allowed_types.join(", ")}"
|
40
|
+
message << "#{@missing_allowed_types.join(", ")} were rejected"
|
41
|
+
end
|
42
|
+
|
43
|
+
if @rejected_types
|
44
|
+
message << "Reject content types: #{rejected_types.join(", ")}"
|
45
|
+
message << "#{@missing_rejected_types.join(", ")} were accepted"
|
46
|
+
end
|
41
47
|
|
42
|
-
|
43
|
-
#{rejected_types_and_failures}
|
44
|
-
MESSAGE
|
48
|
+
message.join("\n")
|
45
49
|
end
|
46
50
|
|
47
51
|
protected
|
@@ -57,7 +61,7 @@ module ActiveStorageValidations
|
|
57
61
|
end
|
58
62
|
|
59
63
|
def rejected_types
|
60
|
-
@rejected_types ||
|
64
|
+
@rejected_types || []
|
61
65
|
end
|
62
66
|
|
63
67
|
def allowed_types_allowed?
|
@@ -70,22 +74,6 @@ module ActiveStorageValidations
|
|
70
74
|
@missing_rejected_types.none?
|
71
75
|
end
|
72
76
|
|
73
|
-
def accepted_types_and_failures
|
74
|
-
if @missing_allowed_types.present?
|
75
|
-
"#{@missing_allowed_types.join(", ")} were rejected."
|
76
|
-
else
|
77
|
-
"All were accepted successfully."
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
def rejected_types_and_failures
|
82
|
-
if @missing_rejected_types.present?
|
83
|
-
"#{@missing_rejected_types.join(", ")} were accepted."
|
84
|
-
else
|
85
|
-
"All were rejected successfully."
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
77
|
def type_allowed?(type)
|
90
78
|
@subject.public_send(@attribute_name).attach(attachment_for(type))
|
91
79
|
@subject.validate
|
@@ -96,16 +84,6 @@ module ActiveStorageValidations
|
|
96
84
|
suffix = type.to_s.split('/').last
|
97
85
|
{ io: Tempfile.new('.'), filename: "test.#{suffix}", content_type: type }
|
98
86
|
end
|
99
|
-
|
100
|
-
private
|
101
|
-
|
102
|
-
def content_type_keys
|
103
|
-
if Rails.gem_version < Gem::Version.new('6.1.0')
|
104
|
-
Mime::LOOKUP.keys
|
105
|
-
else
|
106
|
-
Marcel::TYPES.keys
|
107
|
-
end
|
108
|
-
end
|
109
87
|
end
|
110
88
|
end
|
111
89
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module ActiveStorageValidations
|
2
2
|
class Metadata
|
3
|
+
class InvalidImageError < StandardError; end
|
4
|
+
|
3
5
|
attr_reader :file
|
4
6
|
|
5
7
|
def initialize(file)
|
@@ -10,7 +12,7 @@ module ActiveStorageValidations
|
|
10
12
|
def image_processor
|
11
13
|
Rails.application.config.active_storage.variant_processor
|
12
14
|
end
|
13
|
-
|
15
|
+
|
14
16
|
def exception_class
|
15
17
|
if image_processor == :vips && defined?(Vips)
|
16
18
|
Vips::Error
|
@@ -35,6 +37,16 @@ module ActiveStorageValidations
|
|
35
37
|
{ width: image.width, height: image.height }
|
36
38
|
end
|
37
39
|
end
|
40
|
+
rescue InvalidImageError
|
41
|
+
logger.info "Skipping image analysis because ImageMagick or Vips doesn't support the file"
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
|
45
|
+
def valid?
|
46
|
+
read_image
|
47
|
+
true
|
48
|
+
rescue InvalidImageError
|
49
|
+
false
|
38
50
|
end
|
39
51
|
|
40
52
|
private
|
@@ -76,12 +88,9 @@ module ActiveStorageValidations
|
|
76
88
|
end
|
77
89
|
end
|
78
90
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
logger.info "Skipping image analysis because ImageMagick or Vips doesn't support the file"
|
83
|
-
{}
|
84
|
-
end
|
91
|
+
|
92
|
+
raise InvalidImageError unless valid_image?(image)
|
93
|
+
yield image
|
85
94
|
rescue LoadError, NameError
|
86
95
|
logger.info "Skipping image analysis because the mini_magick or ruby-vips gem isn't installed"
|
87
96
|
{}
|
@@ -93,6 +102,8 @@ module ActiveStorageValidations
|
|
93
102
|
end
|
94
103
|
|
95
104
|
def valid_image?(image)
|
105
|
+
return false unless image
|
106
|
+
|
96
107
|
image_processor == :vips && image.is_a?(Vips::Image) ? image.avg : image.valid?
|
97
108
|
rescue exception_class
|
98
109
|
false
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module ActiveStorageValidations
|
2
2
|
module OptionProcUnfolding
|
3
3
|
|
4
|
-
def unfold_procs(record, object, only_keys
|
4
|
+
def unfold_procs(record, object, only_keys)
|
5
5
|
case object
|
6
6
|
when Hash
|
7
|
-
object.merge(object) { |key, value| only_keys&.exclude?(key) ?
|
7
|
+
object.merge(object) { |key, value| only_keys&.exclude?(key) ? {} : unfold_procs(record, value, nil) }
|
8
8
|
when Array
|
9
9
|
object.map { |o| unfold_procs(record, o, only_keys) }
|
10
10
|
else
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'metadata.rb'
|
4
|
+
|
5
|
+
module ActiveStorageValidations
|
6
|
+
class ProcessableImageValidator < ActiveModel::EachValidator # :nodoc
|
7
|
+
include OptionProcUnfolding
|
8
|
+
|
9
|
+
if Rails.gem_version >= Gem::Version.new('6.0.0')
|
10
|
+
def validate_each(record, attribute, _value)
|
11
|
+
return true unless record.send(attribute).attached?
|
12
|
+
|
13
|
+
changes = record.attachment_changes[attribute.to_s]
|
14
|
+
return true if changes.blank?
|
15
|
+
|
16
|
+
files = Array.wrap(changes.is_a?(ActiveStorage::Attached::Changes::CreateMany) ? changes.attachables : changes.attachable)
|
17
|
+
|
18
|
+
files.each do |file|
|
19
|
+
add_error(record, attribute, :image_not_processable) unless Metadata.new(file).valid?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
# Rails 5
|
24
|
+
def validate_each(record, attribute, _value)
|
25
|
+
return true unless record.send(attribute).attached?
|
26
|
+
|
27
|
+
files = Array.wrap(record.send(attribute))
|
28
|
+
|
29
|
+
files.each do |file|
|
30
|
+
add_error(record, attribute, :image_not_processable) unless Metadata.new(file).valid?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def add_error(record, attribute, default_message)
|
38
|
+
message = options[:message].presence || default_message
|
39
|
+
return if record.errors.added?(attribute, message)
|
40
|
+
record.errors.add(attribute, message)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -9,6 +9,7 @@ require 'active_storage_validations/size_validator'
|
|
9
9
|
require 'active_storage_validations/limit_validator'
|
10
10
|
require 'active_storage_validations/dimension_validator'
|
11
11
|
require 'active_storage_validations/aspect_ratio_validator'
|
12
|
+
require 'active_storage_validations/processable_image_validator'
|
12
13
|
|
13
14
|
ActiveSupport.on_load(:active_record) do
|
14
15
|
send :include, ActiveStorageValidations
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_storage_validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Igor Kasyanchuk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -216,6 +216,7 @@ files:
|
|
216
216
|
- lib/active_storage_validations/matchers/size_validator_matcher.rb
|
217
217
|
- lib/active_storage_validations/metadata.rb
|
218
218
|
- lib/active_storage_validations/option_proc_unfolding.rb
|
219
|
+
- lib/active_storage_validations/processable_image_validator.rb
|
219
220
|
- lib/active_storage_validations/railtie.rb
|
220
221
|
- lib/active_storage_validations/size_validator.rb
|
221
222
|
- lib/active_storage_validations/version.rb
|