active_storage_validations 3.0.5 → 4.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/MIT-LICENSE +1 -1
- data/README.md +227 -116
- data/Rakefile +13 -15
- data/config/locales/da.yml +2 -0
- data/config/locales/de.yml +2 -0
- data/config/locales/en-GB.yml +2 -0
- data/config/locales/en.yml +2 -0
- data/config/locales/es.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/it.yml +2 -0
- data/config/locales/ja.yml +2 -0
- data/config/locales/nl.yml +2 -0
- data/config/locales/pl.yml +2 -0
- data/config/locales/pt-BR.yml +2 -0
- data/config/locales/ru.yml +2 -0
- data/config/locales/sv.yml +2 -0
- data/config/locales/tr.yml +2 -0
- data/config/locales/uk.yml +2 -0
- data/config/locales/vi.yml +2 -0
- data/config/locales/zh-CN.yml +2 -0
- data/lib/active_storage_validations/analyzer/audio_analyzer.rb +0 -1
- data/lib/active_storage_validations/analyzer/content_type_analyzer/file.rb +31 -0
- data/lib/active_storage_validations/analyzer/content_type_analyzer/magika.rb +44 -0
- data/lib/active_storage_validations/analyzer/content_type_analyzer.rb +15 -24
- data/lib/active_storage_validations/analyzer/image_analyzer/image_magick.rb +41 -7
- data/lib/active_storage_validations/analyzer/image_analyzer/vips.rb +36 -10
- data/lib/active_storage_validations/analyzer/pdf_analyzer.rb +3 -9
- data/lib/active_storage_validations/analyzer/shared/asv_ff_probable.rb +5 -4
- data/lib/active_storage_validations/analyzer/video_analyzer.rb +0 -1
- data/lib/active_storage_validations/analyzer.rb +35 -3
- data/lib/active_storage_validations/content_type_validator.rb +24 -6
- data/lib/active_storage_validations/dimension_validator.rb +4 -2
- data/lib/active_storage_validations/form_builder.rb +43 -0
- data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +4 -0
- data/lib/active_storage_validations/matchers/base_comparison_validator_matcher.rb +11 -1
- data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +12 -0
- data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/duration_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/limit_validator_matcher.rb +4 -0
- data/lib/active_storage_validations/matchers/pages_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/processable_file_validator_matcher.rb +8 -0
- data/lib/active_storage_validations/matchers/shared/asv_except_onable.rb +57 -0
- data/lib/active_storage_validations/matchers/shared/asv_spoofing_protectable.rb +44 -0
- data/lib/active_storage_validations/matchers/shared/asv_timeoutable.rb +32 -0
- data/lib/active_storage_validations/matchers/with_audio_validator_matcher.rb +114 -0
- data/lib/active_storage_validations/matchers.rb +10 -1
- data/lib/active_storage_validations/processable_file_validator.rb +60 -1
- data/lib/active_storage_validations/railtie.rb +6 -0
- data/lib/active_storage_validations/shared/asv_analyzable.rb +66 -8
- data/lib/active_storage_validations/shared/asv_attachable.rb +9 -10
- data/lib/active_storage_validations/shared/asv_commandable.rb +95 -0
- data/lib/active_storage_validations/shared/asv_optionable.rb +5 -1
- data/lib/active_storage_validations/version.rb +1 -1
- data/lib/active_storage_validations/with_audio_validator.rb +37 -0
- data/lib/active_storage_validations.rb +23 -0
- metadata +27 -58
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 24d8643d1f970252124d4429ca9bc15b222ef203cdcae93427a0860c7190c370
|
|
4
|
+
data.tar.gz: 62a74e517b40b32dba39c0529f0d4e4529d615a11decdebf8ec338505c082435
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8fa701638b13eea05351e5a76847d144e93ec83b4e14a8d5b5e23ae71944eabd092704c723fcb81e9c44a3fb909ab6431be680390ee414f13002af671792ca1
|
|
7
|
+
data.tar.gz: 82af6984104d830cd7eda7ffdb557f3bb997d8bb59fbef6edc85e0830c3a4397209d4ab31f6427f5945fe392935fefe7c49dc6cabd87c840a34592e8b827f300
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
# Active Storage Validations
|
|
5
5
|
|
|
6
|
-
[](https://github.com/igorkasyanchuk/active_storage_validations/actions/workflows/main.yml)
|
|
7
7
|
[](https://www.railsjazz.com)
|
|
8
8
|
[](https://www.patreon.com/igorkasyanchuk)
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
Active Storage Validations is a gem that allows you to add validations for Active Storage attributes.
|
|
13
13
|
|
|
14
|
-
This
|
|
14
|
+
This gem is doing it right for you! Just use `validates :avatar, attached: true, content_type: 'image/png'` and that's it!
|
|
15
15
|
|
|
16
16
|
## Table of Contents
|
|
17
17
|
|
|
@@ -22,6 +22,7 @@ This gems is doing it right for you! Just use `validates :avatar, attached: true
|
|
|
22
22
|
- [Using video and audio metadata validators](#using-video-and-audio-metadata-validators)
|
|
23
23
|
- [Using pdf metadata validators](#using-pdf-metadata-validators)
|
|
24
24
|
- [Using content type spoofing protection validator option](#using-content-type-spoofing-protection-validator-option)
|
|
25
|
+
- [Configuration](#configuration)
|
|
25
26
|
- [Validators](#validators)
|
|
26
27
|
- [Attached](#attached)
|
|
27
28
|
- [Limit](#limit)
|
|
@@ -30,11 +31,11 @@ This gems is doing it right for you! Just use `validates :avatar, attached: true
|
|
|
30
31
|
- [Total size](#total-size)
|
|
31
32
|
- [Dimension](#dimension)
|
|
32
33
|
- [Duration](#duration)
|
|
34
|
+
- [With audio](#with-audio)
|
|
33
35
|
- [Aspect ratio](#aspect-ratio)
|
|
34
36
|
- [Processable file](#processable-file)
|
|
35
37
|
- [Pages](#pages)
|
|
36
|
-
- [Upgrading
|
|
37
|
-
- [Upgrading from 2.x to 3.x](#upgrading-from-2x-to-3x)
|
|
38
|
+
- [Upgrading](#upgrading)
|
|
38
39
|
- [Internationalization (I18n)](#internationalization-i18n)
|
|
39
40
|
- [Test matchers](#test-matchers)
|
|
40
41
|
- [Contributing](#contributing)
|
|
@@ -44,7 +45,7 @@ This gems is doing it right for you! Just use `validates :avatar, attached: true
|
|
|
44
45
|
|
|
45
46
|
### Installation
|
|
46
47
|
|
|
47
|
-
Active Storage Validations work with Rails
|
|
48
|
+
Active Storage Validations work with Rails 7.0.1 onwards and Ruby 3.3 onwards. Add this line to your application's Gemfile:
|
|
48
49
|
|
|
49
50
|
```ruby
|
|
50
51
|
gem 'active_storage_validations'
|
|
@@ -65,16 +66,18 @@ Once you have installed the gem, I18n error messages will be added automatically
|
|
|
65
66
|
Optionally, to use the image metadata validators (`dimension`, `aspect_ratio` and `processable_file`), you will have to add one of the corresponding gems:
|
|
66
67
|
|
|
67
68
|
```ruby
|
|
68
|
-
gem 'mini_magick', '>= 4.9.5'
|
|
69
|
-
# Or
|
|
70
69
|
gem 'ruby-vips', '>= 2.1.0'
|
|
70
|
+
# Or
|
|
71
|
+
gem 'mini_magick', '>= 4.9.5'
|
|
71
72
|
```
|
|
72
73
|
|
|
73
|
-
Plus, you have to be sure to have the corresponding command-line tool installed on your system
|
|
74
|
+
Plus, you have to be sure to have the corresponding command-line tool installed on your system (`libvips` for `ruby-vips`, or ImageMagick for `mini_magick` — both locally and in CI / production).
|
|
75
|
+
|
|
76
|
+
We recommend **libvips** (`ruby-vips` + `config.active_storage.variant_processor = :vips`) for these validators. Rails already defaults Active Storage variants to libvips ([`ActiveStorage::Variant`](https://api.rubyonrails.org/classes/ActiveStorage/Variant.html)), and our [image processor benchmarks](benchmark/BASELINE.md#image-processors--vips-vs-mini_magick) show cold metadata analysis is about **8× faster** than MiniMagick/ImageMagick on the same machine and fixtures. Warm validations (cached `asv_*` metadata) are similar for both.
|
|
74
77
|
|
|
75
78
|
### Using video and audio metadata validators
|
|
76
79
|
|
|
77
|
-
To use the video and audio metadata validators (`dimension`, `aspect_ratio`, `processable_file` and `
|
|
80
|
+
To use the video and audio metadata validators (`dimension`, `aspect_ratio`, `processable_file`, `duration` and `with_audio`), you will not need to add any gems. However you will need to have the `ffmpeg` command-line tool installed on your system (once again, be sure to have it installed both on your local and in your CI / production environments).
|
|
78
81
|
|
|
79
82
|
### Using pdf metadata validators
|
|
80
83
|
|
|
@@ -82,9 +85,51 @@ To use the pdf metadata validators (`dimension`, `aspect_ratio`, `processable_fi
|
|
|
82
85
|
|
|
83
86
|
### Using content type spoofing protection validator option
|
|
84
87
|
|
|
85
|
-
To use the `spoofing_protection` option with the `content_type` validator
|
|
88
|
+
To use the `spoofing_protection` option with the `content_type` validator:
|
|
89
|
+
|
|
90
|
+
- Default backend (`true` / `:file`): the UNIX [`file`](https://en.wikipedia.org/wiki/File_(command)) command (usually preinstalled on UNIX systems)
|
|
91
|
+
- Magika backend (`:magika`): the [Google Magika](https://github.com/google/magika) CLI — install via `brew install magika`, their [install script](https://securityresearch.google/magika/getting-started/installation/), `cargo install --locked magika-cli`, or `pipx install magika`
|
|
92
|
+
|
|
93
|
+
Both backends are optional system tools (not Ruby gems). Prefer `:magika` when you can install the CLI — it is generally more accurate than `file`, especially on textual / ambiguous formats. Be sure to install Magika in CI / production if you enable `:magika`.
|
|
94
|
+
|
|
95
|
+
If you want some inspiration about how to add `imagemagick`, `libvips`, `ffmpeg`, `poppler` or `magika` to your docker image, you can check how we do it for the gem CI (https://github.com/igorkasyanchuk/active_storage_validations/blob/master/.github/workflows/main.yml)
|
|
96
|
+
|
|
97
|
+
### Configuration
|
|
98
|
+
|
|
99
|
+
Optional global settings can go in an initializer. Example template:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
# config/initializers/active_storage_validations.rb
|
|
103
|
+
ActiveStorageValidations.configure do |config|
|
|
104
|
+
# Infer HTML accept= on file_field from content_type validators (default: true)
|
|
105
|
+
# config.infer_file_field_accept = false
|
|
106
|
+
|
|
107
|
+
# Max time for external analyzer commands: ffprobe, pdfinfo, file, magika, ImageMagick identify, libvips
|
|
108
|
+
# (default: 10.seconds; set to nil to disable)
|
|
109
|
+
# config.command_timeout = 10.seconds
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Optional: monitor analyzer timeouts
|
|
113
|
+
# ActiveSupport::Notifications.subscribe("timeout.active_storage_validations") do |*args|
|
|
114
|
+
# event = ActiveSupport::Notifications::Event.new(*args)
|
|
115
|
+
# Rails.logger.warn("[ASV] command timeout: #{event.payload}")
|
|
116
|
+
# end
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`command_timeout` bounds metadata analysis used by `dimension`, `aspect_ratio`, `duration`, `with_audio`, `pages`, `processable_file`, and `content_type` (with `spoofing_protection`). When a command times out, analysis fails closed and the validator adds its usual error (`file_not_processable` / `media_metadata_missing` / `audio_missing` / content-type errors) — there is no separate timeout error message.
|
|
120
|
+
|
|
121
|
+
The 10s default is enough for typical uploads. Raise it (or set `nil`) if you analyze very large videos/PDFs, especially on slow or network storage — otherwise those files can start failing validation after upgrade. See [upgrade to 4.x](docs/upgrade_to_4.md#analyzer-command-timeout).
|
|
122
|
+
|
|
123
|
+
Per-validator override (applies to the analysis triggered by that validator; the first analysis for a blob is cached):
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
validates :video, duration: { less_than: 5.minutes, timeout: 30.seconds }
|
|
127
|
+
```
|
|
86
128
|
|
|
87
|
-
|
|
129
|
+
Notes:
|
|
130
|
+
- Setting `command_timeout` (or per-validator `timeout:`) to `nil` disables the deadline
|
|
131
|
+
- ImageMagick analysis runs `identify` through the same killable command runner (MiniMagick is only used to build the argv)
|
|
132
|
+
- For libvips, a timeout may not immediately free the Ruby thread stuck in FFI/C; the validation still fails closed and emits `timeout.active_storage_validations`
|
|
88
133
|
|
|
89
134
|
## Validators
|
|
90
135
|
|
|
@@ -96,6 +141,7 @@ If you want some inspiration about how to add `imagemagick`, `libvips`, `ffmpeg`
|
|
|
96
141
|
- [Total size](#total-size): validates total file size for several files
|
|
97
142
|
- [Dimension](#dimension): validates image / video dimensions
|
|
98
143
|
- [Duration](#duration): validates video / audio duration
|
|
144
|
+
- [With audio](#with-audio): validates whether a video contains an audio track
|
|
99
145
|
- [Aspect ratio](#aspect-ratio): validates image / video aspect ratio
|
|
100
146
|
- [Processable file](#processable-file): validates if a file can be processed
|
|
101
147
|
- [Pages](#pages): validates pdf number of pages
|
|
@@ -205,10 +251,11 @@ Validates if the attachment has an allowed content type.
|
|
|
205
251
|
|
|
206
252
|
#### Options
|
|
207
253
|
|
|
208
|
-
The `content_type` validator has
|
|
254
|
+
The `content_type` validator has several possible options:
|
|
209
255
|
- `with`: defines the allowed content type (string, symbol or regex)
|
|
210
256
|
- `in`: defines the allowed content types (array of strings or symbols)
|
|
211
|
-
- `spoofing_protection`: enables content type spoofing protection (
|
|
257
|
+
- `spoofing_protection`: enables content type spoofing protection (`false` by default). Allowed values: `true` / `:file` (UNIX `file` CLI), `:magika` (Google Magika CLI)
|
|
258
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) when spoofing protection runs `file` or `magika`
|
|
212
259
|
|
|
213
260
|
As mentioned above, this validator can define content types in several ways:
|
|
214
261
|
- String: `image/png` or `png`
|
|
@@ -226,32 +273,55 @@ class User < ApplicationRecord
|
|
|
226
273
|
validates :avatar, content_type: :png # only allows PNG images, same as { with: :png }
|
|
227
274
|
validates :avatar, content_type: /\Avideo\/.*\z/ # only allows video files
|
|
228
275
|
validates :avatar, content_type: ['image/png', 'image/jpeg'] # only allows PNG and JPEG images
|
|
229
|
-
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: true } #
|
|
276
|
+
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: true } # UNIX `file` backend (same as :file)
|
|
277
|
+
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: :magika } # Google Magika CLI backend
|
|
278
|
+
# Stronger protection for media/PDF: sniff + parse
|
|
279
|
+
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: true }, processable_file: true
|
|
230
280
|
end
|
|
231
281
|
```
|
|
232
282
|
|
|
233
|
-
####
|
|
283
|
+
#### HTML `accept` attribute (FormBuilder)
|
|
234
284
|
|
|
235
|
-
When using
|
|
285
|
+
When using Rails' `FormBuilder#file_field`, the gem automatically sets the HTML [`accept`](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept) attribute from your `content_type` validators. This improves UX by filtering selectable files in the browser dialog. It is only a frontend hint: a malicious user can still submit disallowed types, so keep the backend validation.
|
|
236
286
|
|
|
237
|
-
For example, if you want to allow PNG and JPEG images only, you can do this:
|
|
238
287
|
```ruby
|
|
239
288
|
class User < ApplicationRecord
|
|
240
|
-
ACCEPTED_CONTENT_TYPES = ['image/png', 'image/jpeg'].freeze
|
|
241
|
-
|
|
242
289
|
has_one_attached :avatar
|
|
243
290
|
|
|
244
|
-
validates :avatar, content_type:
|
|
291
|
+
validates :avatar, content_type: ['image/png', 'image/jpeg']
|
|
245
292
|
end
|
|
246
293
|
```
|
|
247
294
|
|
|
248
295
|
```erb
|
|
249
296
|
<%= form_with model: @user do |f| %>
|
|
250
|
-
<%= f.file_field :avatar
|
|
251
|
-
|
|
297
|
+
<%= f.file_field :avatar %>
|
|
298
|
+
<%# => <input type="file" accept="image/png,image/jpeg" ...> %>
|
|
252
299
|
<% end %>
|
|
253
300
|
```
|
|
254
301
|
|
|
302
|
+
Explicit `accept` values are never overridden. You can also disable inference:
|
|
303
|
+
|
|
304
|
+
```erb
|
|
305
|
+
<%# Per field %>
|
|
306
|
+
<%= f.file_field :avatar, infer_accept: false %>
|
|
307
|
+
|
|
308
|
+
<%# Or set a custom accept value %>
|
|
309
|
+
<%= f.file_field :avatar, accept: "image/*" %>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
```ruby
|
|
313
|
+
# Globally — see [Configuration](#configuration) for a full initializer template
|
|
314
|
+
ActiveStorageValidations.infer_file_field_accept = false
|
|
315
|
+
|
|
316
|
+
# Equivalent:
|
|
317
|
+
ActiveStorageValidations.configure { |config| config.infer_file_field_accept = false }
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Notes:
|
|
321
|
+
- Only broad MIME-type regexes of the form `/\Aimage\/.*\z/` (or `video` / `audio` / etc.) are inferred, as `image/*`
|
|
322
|
+
- Other regexes (e.g. `/\Aimage\/(png|gif)\z/`) and Proc / dynamic `content_type` options are skipped, since they cannot be reliably represented in `accept`
|
|
323
|
+
- Conditional validators (`if:` / `unless:`) are not evaluated: their content types are always included in `accept`, even when the condition would skip the validator for that record. Backend validation is unchanged; use `infer_accept: false` (or a custom `accept:`) if the picker must match the active conditions
|
|
324
|
+
|
|
255
325
|
#### Content type shorthands
|
|
256
326
|
|
|
257
327
|
If you choose to use a content_type 'shorthand' (like `png`), note that it will be converted to a full content type using `Marcel::MimeType.for` under the hood. Therefore, you should check if the content_type is registered by [`Marcel::EXTENSIONS`](https://github.com/rails/marcel/blob/main/lib/marcel/tables.rb). If it's not, you can register it by adding the following code to your `config/initializers/mime_types.rb` file:
|
|
@@ -264,7 +334,15 @@ Be sure to at least include one the `extensions`, `parents` or `magic` option, o
|
|
|
264
334
|
|
|
265
335
|
#### Content type spoofing protection
|
|
266
336
|
|
|
267
|
-
By default, the gem does not prevent content type spoofing.
|
|
337
|
+
By default, the gem does not prevent content type spoofing. Enable it with `spoofing_protection`:
|
|
338
|
+
|
|
339
|
+
```ruby
|
|
340
|
+
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: true } # => :file (UNIX file CLI)
|
|
341
|
+
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: :file } # explicit
|
|
342
|
+
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: :magika } # Google Magika CLI
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Override binary paths with `ActiveStorage.paths[:file]` / `ActiveStorage.paths[:magika]` if needed.
|
|
268
346
|
|
|
269
347
|
<details>
|
|
270
348
|
<summary>
|
|
@@ -279,9 +357,22 @@ File content type spoofing happens when an ill-intentioned user uploads a file w
|
|
|
279
357
|
How do we prevent it?
|
|
280
358
|
</summary>
|
|
281
359
|
|
|
282
|
-
|
|
360
|
+
Spoofing protection compares the declared Active Storage content type to a type detected by a sniffer CLI, then uses `Marcel` parent types so near-matches still pass:
|
|
361
|
+
|
|
362
|
+
- `:file` (default) — UNIX `file` / libmagic, mostly magic bytes / headers. Zero extra install on most UNIX systems.
|
|
363
|
+
- `:magika` — [Google Magika](https://github.com/google/magika) CLI (ML sniffer; samples begin/middle/end of the file). Generally more accurate than `file`, especially on textual / ambiguous formats (Google reports ~99% F1 vs ~88% for `file --mime` on overlapping types). Prefer `:magika` when you can install the CLI.
|
|
364
|
+
|
|
365
|
+
Neither backend fully parses the file. They do **not** load the whole file into RAM. For already-persisted blobs (e.g. remote storage), the analyzer still downloads the blob to a local tempfile before sniffing. That download is streamed in chunks to disk, but it can still be costly for very large files. Local path uploads are analyzed in place.
|
|
366
|
+
|
|
367
|
+
Detected types are cached on the blob as `asv_content_type` + `asv_content_type_backend`. Switching backend re-analyzes. Legacy blobs that only have `asv_content_type` (no backend key) are treated as `:file` and keep using the cache — they are not re-analyzed.
|
|
283
368
|
|
|
284
|
-
|
|
369
|
+
Sniffers will not always return the exact same MIME as Active Storage (AS uses first ~4kb + filename + extension). Close parent types are accepted via `Marcel::TYPE_PARENTS` (e.g. `video/x-ms-wmv` vs `video/x-ms-asf`).
|
|
370
|
+
|
|
371
|
+
For stronger protection on images / video / audio / PDF, combine sniffing with parse validation:
|
|
372
|
+
|
|
373
|
+
```ruby
|
|
374
|
+
validates :avatar, content_type: { in: [:png, :jpeg], spoofing_protection: true }, processable_file: true
|
|
375
|
+
```
|
|
285
376
|
</details>
|
|
286
377
|
|
|
287
378
|
<details>
|
|
@@ -289,9 +380,11 @@ Take note that the `file` analyzer will not find the exactly same content type a
|
|
|
289
380
|
Edge cases
|
|
290
381
|
</summary>
|
|
291
382
|
|
|
292
|
-
The difficulty to accurately predict a mime type may generate false positives, if so there are
|
|
293
|
-
-
|
|
294
|
-
-
|
|
383
|
+
The difficulty to accurately predict a mime type may generate false positives, if so there are several solutions available:
|
|
384
|
+
- Try the other sniffer backend (`:file` vs `:magika`)
|
|
385
|
+
- For media/PDF that sniffers misidentify but that open correctly, add `processable_file: true`
|
|
386
|
+
- If the ActiveStorage blob content type is closely related to the detected content type, enhance `Marcel::TYPE_PARENTS` mapping using `Marcel::MimeType.extend "application/x-rar-compressed", parents: %(application/x-rar)` in the `config/initializers/mime_types.rb` file. (Please drop an issue so we can add it to the gem for everyone!)
|
|
387
|
+
- If needed, disable spoofing protection in the validator, and please drop us an issue so we can fix it for everyone!
|
|
295
388
|
</details>
|
|
296
389
|
|
|
297
390
|
|
|
@@ -326,7 +419,7 @@ Validates each attached file size.
|
|
|
326
419
|
|
|
327
420
|
#### Options
|
|
328
421
|
|
|
329
|
-
The `size` validator has
|
|
422
|
+
The `size` validator has 6 possible options:
|
|
330
423
|
- `less_than`: defines the strict maximum allowed file size
|
|
331
424
|
- `less_than_or_equal_to`: defines the maximum allowed file size
|
|
332
425
|
- `greater_than`: defines the strict minimum allowed file size
|
|
@@ -384,7 +477,7 @@ Validates the total file size for several files.
|
|
|
384
477
|
|
|
385
478
|
#### Options
|
|
386
479
|
|
|
387
|
-
The `total_size` validator has
|
|
480
|
+
The `total_size` validator has 6 possible options:
|
|
388
481
|
- `less_than`: defines the strict maximum allowed total file size
|
|
389
482
|
- `less_than_or_equal_to`: defines the maximum allowed total file size
|
|
390
483
|
- `greater_than`: defines the strict minimum allowed total file size
|
|
@@ -434,7 +527,7 @@ The `total_size` validator error messages expose 4 values that you can use:
|
|
|
434
527
|
|
|
435
528
|
Validates the dimension of the attached image / video files.
|
|
436
529
|
It can also be used for pdf files, but it will only analyze the pdf first page, and will assume a DPI of 72.
|
|
437
|
-
(be sure to have the right dependencies installed as mentioned in [
|
|
530
|
+
(be sure to have the right dependencies installed as mentioned in [Getting started](#getting-started))
|
|
438
531
|
|
|
439
532
|
#### Options
|
|
440
533
|
|
|
@@ -449,6 +542,7 @@ The `dimension` validator has several possible options:
|
|
|
449
542
|
- `in`: defines the allowed height range (range)
|
|
450
543
|
- `min`: defines the minimum allowed width and height (range)
|
|
451
544
|
- `max`: defines the maximum allowed width and height (range)
|
|
545
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) for this validation
|
|
452
546
|
|
|
453
547
|
#### Examples
|
|
454
548
|
|
|
@@ -499,17 +593,18 @@ The `dimension` validator error messages expose 6 values that you can use:
|
|
|
499
593
|
### Duration
|
|
500
594
|
|
|
501
595
|
Validates the duration of the attached audio / video files.
|
|
502
|
-
(be sure to have the right dependencies installed as mentioned in [
|
|
596
|
+
(be sure to have the right dependencies installed as mentioned in [Using video and audio metadata validators](#using-video-and-audio-metadata-validators))
|
|
503
597
|
|
|
504
598
|
#### Options
|
|
505
599
|
|
|
506
|
-
The `duration` validator has
|
|
600
|
+
The `duration` validator has several possible options:
|
|
507
601
|
- `less_than`: defines the strict maximum allowed file duration
|
|
508
602
|
- `less_than_or_equal_to`: defines the maximum allowed file duration
|
|
509
603
|
- `greater_than`: defines the strict minimum allowed file duration
|
|
510
604
|
- `greater_than_or_equal_to`: defines the minimum allowed file duration
|
|
511
605
|
- `between`: defines the allowed file duration range
|
|
512
606
|
- `equal_to`: defines the allowed duration
|
|
607
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) for this validation
|
|
513
608
|
|
|
514
609
|
#### Examples
|
|
515
610
|
|
|
@@ -524,6 +619,7 @@ class User < ApplicationRecord
|
|
|
524
619
|
validates :intro_song, duration: { greater_than_or_equal_to: 1.second } # restricts the file duration to >= 1 second
|
|
525
620
|
validates :intro_song, duration: { between: 1.second..2.minutes } # restricts the file duration to between 1 second and 2 minutes
|
|
526
621
|
validates :intro_song, duration: { equal_to: 1.minute } # restricts the duration to exactly 1 minute
|
|
622
|
+
validates :intro_song, duration: { less_than: 5.minutes, timeout: 5.seconds } # custom analyzer timeout
|
|
527
623
|
end
|
|
528
624
|
```
|
|
529
625
|
|
|
@@ -550,17 +646,59 @@ The `duration` validator error messages expose 4 values that you can use:
|
|
|
550
646
|
|
|
551
647
|
---
|
|
552
648
|
|
|
649
|
+
### With audio
|
|
650
|
+
|
|
651
|
+
Validates whether attached video files contain an audio track.
|
|
652
|
+
(be sure to have the right dependencies installed as mentioned in [Using video and audio metadata validators](#using-video-and-audio-metadata-validators))
|
|
653
|
+
|
|
654
|
+
#### Options
|
|
655
|
+
|
|
656
|
+
The `with_audio` validator supports:
|
|
657
|
+
- `with`: `true` requires an audio track and `false` rejects one
|
|
658
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) for this validation
|
|
659
|
+
|
|
660
|
+
#### Examples
|
|
661
|
+
|
|
662
|
+
Use it like this:
|
|
663
|
+
```ruby
|
|
664
|
+
class User < ApplicationRecord
|
|
665
|
+
has_one_attached :video
|
|
666
|
+
has_one_attached :silent_video
|
|
667
|
+
|
|
668
|
+
validates :video, with_audio: true
|
|
669
|
+
validates :silent_video, with_audio: { with: false }
|
|
670
|
+
validates :video, with_audio: { timeout: 5.seconds }
|
|
671
|
+
end
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
Rails treats a bare `with_audio: false` as a disabled validator. Use the hash form `with_audio: { with: false }` to reject videos that contain audio.
|
|
675
|
+
|
|
676
|
+
#### Error messages (I18n)
|
|
677
|
+
|
|
678
|
+
```yml
|
|
679
|
+
en:
|
|
680
|
+
errors:
|
|
681
|
+
messages:
|
|
682
|
+
audio_missing: "must have an audio track"
|
|
683
|
+
audio_present: "must not have an audio track"
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
The `with_audio` validator error message exposes the `filename` value containing the current file name.
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
553
690
|
### Aspect ratio
|
|
554
691
|
|
|
555
692
|
Validates the aspect ratio of the attached image / video files.
|
|
556
693
|
It can also be used for pdf files, but it will only analyze the pdf first page.
|
|
557
|
-
(be sure to have the right dependencies installed as mentioned in [
|
|
694
|
+
(be sure to have the right dependencies installed as mentioned in [Getting started](#getting-started))
|
|
558
695
|
|
|
559
696
|
#### Options
|
|
560
697
|
|
|
561
698
|
The `aspect_ratio` validator has several options:
|
|
562
699
|
- `with`: defines the allowed aspect ratio (e.g. `:is_16/9`)
|
|
563
700
|
- `in`: defines the allowed aspect ratios (e.g. `%i[square landscape]`)
|
|
701
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) for this validation
|
|
564
702
|
|
|
565
703
|
This validator can define aspect ratios in several ways:
|
|
566
704
|
- Symbols:
|
|
@@ -607,11 +745,12 @@ The `aspect_ratio` validator error messages expose 4 values that you can use:
|
|
|
607
745
|
### Processable file
|
|
608
746
|
|
|
609
747
|
Validates if the attached files can be processed by MiniMagick or Vips (image), ffmpeg (video/audio) or poppler (pdf).
|
|
610
|
-
(be sure to have the right dependencies installed as mentioned in [
|
|
748
|
+
(be sure to have the right dependencies installed as mentioned in [Getting started](#getting-started))
|
|
611
749
|
|
|
612
750
|
#### Options
|
|
613
751
|
|
|
614
|
-
The `processable_file` validator
|
|
752
|
+
The `processable_file` validator supports:
|
|
753
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) for this validation
|
|
615
754
|
|
|
616
755
|
#### Examples
|
|
617
756
|
|
|
@@ -621,9 +760,14 @@ class User < ApplicationRecord
|
|
|
621
760
|
has_one_attached :avatar
|
|
622
761
|
|
|
623
762
|
validates :avatar, processable_file: true # ensures that the file is processable by MiniMagick or Vips (image) or ffmpeg (video/audio)
|
|
763
|
+
validates :avatar, processable_file: { timeout: 5.seconds }
|
|
624
764
|
end
|
|
625
765
|
```
|
|
626
766
|
|
|
767
|
+
#### Notes
|
|
768
|
+
|
|
769
|
+
Rails 7.2.3.2+ / 8.0.5.1+ / 8.1.3.1+ call `Vips.block_untrusted(true)`, so libvips refuses to load formats marked untrusted (e.g. SVG, BMP). Analysis then returns empty metadata by design. `processable_file` does **not** treat that as failure for those content types. `dimension` / `aspect_ratio` still need width/height — use MiniMagick for those formats, or skip those validators for them.
|
|
770
|
+
|
|
627
771
|
#### Error messages (I18n)
|
|
628
772
|
|
|
629
773
|
```yml
|
|
@@ -641,17 +785,18 @@ The `processable_file` validator error messages expose 1 value that you can use:
|
|
|
641
785
|
### Pages
|
|
642
786
|
|
|
643
787
|
Validates each attached pdf file number of pages.
|
|
644
|
-
(be sure to have the right dependencies installed as mentioned in [
|
|
788
|
+
(be sure to have the right dependencies installed as mentioned in [Using pdf metadata validators](#using-pdf-metadata-validators))
|
|
645
789
|
|
|
646
790
|
#### Options
|
|
647
791
|
|
|
648
|
-
The `pages` validator has
|
|
792
|
+
The `pages` validator has several possible options:
|
|
649
793
|
- `less_than`: defines the strict maximum allowed number of pages
|
|
650
794
|
- `less_than_or_equal_to`: defines the maximum allowed number of pages
|
|
651
795
|
- `greater_than`: defines the strict minimum allowed number of pages
|
|
652
796
|
- `greater_than_or_equal_to`: defines the minimum allowed number of pages
|
|
653
797
|
- `between`: defines the allowed number of pages range
|
|
654
798
|
- `equal_to`: defines the allowed number of pages
|
|
799
|
+
- `timeout`: overrides the global analyzer [command timeout](#configuration) for this validation
|
|
655
800
|
|
|
656
801
|
#### Examples
|
|
657
802
|
|
|
@@ -692,64 +837,11 @@ The `pages` validator error messages expose 5 values that you can use:
|
|
|
692
837
|
|
|
693
838
|
---
|
|
694
839
|
|
|
695
|
-
## Upgrading
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
- `duration` validator has been added for audio / video files
|
|
701
|
-
- `dimension` validator now supports videos
|
|
702
|
-
- `aspect_ratio` validator now supports videos
|
|
703
|
-
- `processable_image` validator is now `processable_file` validator and supports image/video/audio
|
|
704
|
-
- Major performance improvement have been added: we now only perform the expensive io analysis operation on the newly attached files. For previously attached files, we validate them using Rails `ActiveStorage::Blob#metadata` internal mecanism ([more here](https://github.com/rails/rails/blob/main/activestorage/app/models/active_storage/blob/analyzable.rb)).
|
|
705
|
-
- All error messages have been given an upgrade and new variables that you can use
|
|
706
|
-
|
|
707
|
-
But this major version bump also comes with some breaking changes. Below are the main breaking changes you need to be aware of:
|
|
708
|
-
- Error messages
|
|
709
|
-
- We advise you to replace all the v1 translations by the new v2 rather than changing them one by one. A majority of messages have been completely rewritten to be more consistent and easier to understand.
|
|
710
|
-
- If you wish to change them one by one, here is the list of changes to make:
|
|
711
|
-
- Some validator errors have been totally changed:
|
|
712
|
-
- `limit` validator keys have been totally reworked
|
|
713
|
-
- `dimension` validator keys have been totally reworked
|
|
714
|
-
- `content_type` validator keys have been totally reworked
|
|
715
|
-
- `processable_image` validator keys have been totally reworked
|
|
716
|
-
- Some keys have been changed:
|
|
717
|
-
- `image_metadata_missing` has been replaced by `media_metadata_missing`
|
|
718
|
-
- `aspect_ratio_is_not` has been replaced by `aspect_ratio_not_x_y`
|
|
719
|
-
- Some error messages variables names have been changed to improve readability:
|
|
720
|
-
- `aspect_ratio` validator:
|
|
721
|
-
- `aspect_ratio` has been replaced by `authorized_aspect_ratios`
|
|
722
|
-
- `content_type` validator:
|
|
723
|
-
- `authorized_types` has been replaced by `authorized_human_content_types`
|
|
724
|
-
- `size` validator:
|
|
725
|
-
- `min_size` has been replaced by `min`
|
|
726
|
-
- `max_size` has been replaced by `max`
|
|
727
|
-
- `total_size` validator:
|
|
728
|
-
- `min_size` has been replaced by `min`
|
|
729
|
-
- `max_size` has been replaced by `max`
|
|
730
|
-
|
|
731
|
-
- `content_type` validator
|
|
732
|
-
- The `:in` option now only accepts 'valid' content types (ie content types deemed by Marcel as valid).
|
|
733
|
-
- The check was mistakenly only performed on the `:with` option previously. Therefore, invalid content types were accepted in the `:in` option, which is not the expected behavior.
|
|
734
|
-
- This might break some cases when you had for example `content_type: ['image/png', 'image/jpg']`, because `image/jpg` is not a valid content type, it should be replaced by `image/jpeg`.
|
|
735
|
-
- An `ArgumentError` is now raised if `image/jpg` is used to make it easier to fix. You should now only use `image/jpeg`.
|
|
736
|
-
|
|
737
|
-
- `processable_image` validator
|
|
738
|
-
- The validator has been replaced by `processable_file` validator, be sure to replace `processable_image: true` to `processable_file: true`
|
|
739
|
-
- The associated matcher has also been updated accordingly, be sure to replace `validate_processable_image_of` to `validate_processable_file_of`
|
|
740
|
-
|
|
741
|
-
## Upgrading from 2.x to 3.x
|
|
742
|
-
|
|
743
|
-
Version 3 comes with the ability to support single page pdf `dimension` / `aspect_ratio` analysis, we had to make a breaking change:
|
|
744
|
-
- To analyze PDFs, you must install the `poppler` PDF processing dependency
|
|
745
|
-
- It's a Rails-supported PDF processing dependency (https://guides.rubyonrails.org/active_storage_overview.html#requirements)
|
|
746
|
-
- To install it, check their documentation at this [link](https://pdf2image.readthedocs.io/en/latest/installation.html).
|
|
747
|
-
- To check if it's installed, execute `pdftoppm -h`.
|
|
748
|
-
- To install this tool in your CI / production environments, you can check how we do it in our own CI (https://github.com/igorkasyanchuk/active_storage_validations/blob/master/.github/workflows/main.yml)
|
|
749
|
-
|
|
750
|
-
We also added the `pages` validator to validate pdf number of pages, and the `equal_to` option to `duration`, `size` and `total_size` validators.
|
|
751
|
-
|
|
752
|
-
Note that, if you do not perform these metadata validations on pdfs, the gem will work the same as in version 2.
|
|
840
|
+
## Upgrading
|
|
841
|
+
|
|
842
|
+
- [Upgrading to 2.x](docs/upgrade_to_2.md)
|
|
843
|
+
- [Upgrading to 3.x](docs/upgrade_to_3.md)
|
|
844
|
+
- [Upgrading to 4.x](docs/upgrade_to_4.md)
|
|
753
845
|
|
|
754
846
|
## Internationalization (I18n)
|
|
755
847
|
|
|
@@ -802,9 +894,11 @@ describe User do
|
|
|
802
894
|
it { is_expected.to validate_limits_of(:avatar).max(5) }
|
|
803
895
|
|
|
804
896
|
# content_type:
|
|
805
|
-
# #allowing, #rejecting
|
|
897
|
+
# #allowing, #rejecting, #spoofing_protection
|
|
806
898
|
it { is_expected.to validate_content_type_of(:avatar).allowing('image/png', 'image/gif') } # possible to use an Array or *splatted array
|
|
807
899
|
it { is_expected.to validate_content_type_of(:avatar).rejecting('text/plain', 'text/xml') } # possible to use an Array or *splatted array
|
|
900
|
+
it { is_expected.to validate_content_type_of(:avatar).allowing('image/png').spoofing_protection } # true / :file
|
|
901
|
+
it { is_expected.to validate_content_type_of(:avatar).allowing('image/png').spoofing_protection(:magika) }
|
|
808
902
|
|
|
809
903
|
# dimension:
|
|
810
904
|
# #width, #height, #width_min, #height_min, #width_max, #height_max, #width_between, #height_between
|
|
@@ -844,6 +938,10 @@ describe User do
|
|
|
844
938
|
it { is_expected.to validate_duration_of(:introduction).between(100..500.seconds) }
|
|
845
939
|
it { is_expected.to validate_duration_of(:avatar).equal_to(5.minutes) }
|
|
846
940
|
|
|
941
|
+
# with_audio
|
|
942
|
+
it { is_expected.to validate_with_audio_of(:video) }
|
|
943
|
+
it { is_expected.to validate_with_audio_of(:silent_video).without_audio }
|
|
944
|
+
|
|
847
945
|
# pages:
|
|
848
946
|
# #less_than, #less_than_or_equal_to, #greater_than, #greater_than_or_equal_to, #between, #equal_to
|
|
849
947
|
it { is_expected.to validate_pages_of(:contract).less_than(50) }
|
|
@@ -856,7 +954,7 @@ end
|
|
|
856
954
|
```
|
|
857
955
|
(Note that matcher methods are chainable)
|
|
858
956
|
|
|
859
|
-
All matchers can currently be customized with
|
|
957
|
+
All matchers can currently be customized with these options:
|
|
860
958
|
|
|
861
959
|
```ruby
|
|
862
960
|
describe User do
|
|
@@ -867,8 +965,17 @@ describe User do
|
|
|
867
965
|
it { is_expected.to validate_attached_of(:avatar).on(:update) }
|
|
868
966
|
it { is_expected.to validate_attached_of(:avatar).on(%i[update custom]) }
|
|
869
967
|
|
|
968
|
+
# :except_on (Rails >= 8.0)
|
|
969
|
+
it { is_expected.to validate_attached_of(:avatar).except_on(:update) }
|
|
970
|
+
it { is_expected.to validate_attached_of(:avatar).except_on(%i[update custom]) }
|
|
971
|
+
|
|
870
972
|
# :message
|
|
871
973
|
it { is_expected.to validate_dimensions_of(:avatar).width(250).with_message('Invalid dimensions.') }
|
|
974
|
+
|
|
975
|
+
# :timeout (analyzer command timeout — metadata validators + content_type with spoofing)
|
|
976
|
+
it { is_expected.to validate_duration_of(:video).less_than(5.minutes).timeout(30.seconds) }
|
|
977
|
+
it { is_expected.to validate_with_audio_of(:video).timeout(5.seconds) }
|
|
978
|
+
it { is_expected.to validate_processable_file_of(:avatar).timeout(5.seconds) }
|
|
872
979
|
end
|
|
873
980
|
```
|
|
874
981
|
|
|
@@ -899,40 +1006,44 @@ Then you can use the matchers with the syntax specified in the RSpec section, ju
|
|
|
899
1006
|
|
|
900
1007
|
If you want to contribute to the project, you will have to fork the repository and create a new branch from the `master` branch. Then build your feature, or fix the issue, and create a pull request. Be sure to add tests for your changes.
|
|
901
1008
|
|
|
1009
|
+
AI coding agents: see [AGENTS.md](AGENTS.md) for architecture, test commands, and contribution patterns. Commit and PR titles follow [Conventional Commits](.cursor/rules/git.mdc).
|
|
1010
|
+
|
|
902
1011
|
Before submitting your pull request, run the tests to make sure everything works as expected.
|
|
903
1012
|
|
|
904
1013
|
To run the gem tests, launch the following commands in the root folder of gem repository:
|
|
905
1014
|
|
|
906
|
-
* `BUNDLE_GEMFILE=gemfiles/
|
|
907
|
-
* `BUNDLE_GEMFILE=gemfiles/
|
|
908
|
-
* `BUNDLE_GEMFILE=gemfiles/
|
|
909
|
-
* `BUNDLE_GEMFILE=gemfiles/
|
|
910
|
-
* `BUNDLE_GEMFILE=gemfiles/
|
|
911
|
-
* `BUNDLE_GEMFILE=gemfiles/
|
|
912
|
-
* `BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake test` to run for Rails main
|
|
1015
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_7_0_1.gemfile bundle exec rake spec` to run for Rails 7.0.1
|
|
1016
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_7_1.gemfile bundle exec rake spec` to run for Rails 7.1
|
|
1017
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_7_2.gemfile bundle exec rake spec` to run for Rails 7.2
|
|
1018
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle exec rake spec` to run for Rails 8.0
|
|
1019
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_8_1.gemfile bundle exec rake spec` to run for Rails 8.1
|
|
1020
|
+
* `BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake spec` to run for Rails main
|
|
913
1021
|
|
|
914
1022
|
Snippet to run in console:
|
|
915
1023
|
|
|
916
1024
|
```bash
|
|
917
|
-
BUNDLE_GEMFILE=gemfiles/
|
|
918
|
-
BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle
|
|
1025
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_0_1.gemfile bundle
|
|
919
1026
|
BUNDLE_GEMFILE=gemfiles/rails_7_1.gemfile bundle
|
|
920
1027
|
BUNDLE_GEMFILE=gemfiles/rails_7_2.gemfile bundle
|
|
921
1028
|
BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle
|
|
922
1029
|
BUNDLE_GEMFILE=gemfiles/rails_8_1.gemfile bundle
|
|
923
1030
|
BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle
|
|
924
|
-
BUNDLE_GEMFILE=gemfiles/
|
|
925
|
-
BUNDLE_GEMFILE=gemfiles/
|
|
926
|
-
BUNDLE_GEMFILE=gemfiles/
|
|
927
|
-
BUNDLE_GEMFILE=gemfiles/
|
|
928
|
-
BUNDLE_GEMFILE=gemfiles/
|
|
929
|
-
BUNDLE_GEMFILE=gemfiles/
|
|
930
|
-
BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake test
|
|
1031
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_0_1.gemfile bundle exec rake spec
|
|
1032
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_1.gemfile bundle exec rake spec
|
|
1033
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_2.gemfile bundle exec rake spec
|
|
1034
|
+
BUNDLE_GEMFILE=gemfiles/rails_8_0.gemfile bundle exec rake spec
|
|
1035
|
+
BUNDLE_GEMFILE=gemfiles/rails_8_1.gemfile bundle exec rake spec
|
|
1036
|
+
BUNDLE_GEMFILE=gemfiles/rails_next.gemfile bundle exec rake spec
|
|
931
1037
|
```
|
|
932
1038
|
|
|
933
1039
|
Tips:
|
|
934
|
-
- To focus
|
|
935
|
-
- To
|
|
1040
|
+
- To focus examples, tag them with `:focus` (or use `fit` / `fdescribe`); RSpec is configured with `filter_run_when_matching :focus`
|
|
1041
|
+
- To run a specific file: `bundle exec rspec spec/validators/size_validator_spec.rb`
|
|
1042
|
+
- Image processor: CI runs both via `IMAGE_PROCESSOR=vips` / `IMAGE_PROCESSOR=mini_magick`. Locally, unset means validators use MiniMagick (ASV default) and both analyzer unit specs run; setting the env selects that processor for validators and excludes the other processor’s tagged examples (so they do not show as pending)
|
|
1043
|
+
|
|
1044
|
+
### Benchmarks
|
|
1045
|
+
|
|
1046
|
+
Optional wall-clock / ips suite for metadata validators (cold analysis vs cached `asv_*` hits) lives under [`benchmark/`](benchmark/). See [`benchmark/README.md`](benchmark/README.md) for setup, how to run, and how to refresh [`benchmark/BASELINE.md`](benchmark/BASELINE.md). CI runs the suite informationally (no fail-on-regression).
|
|
936
1047
|
|
|
937
1048
|
|
|
938
1049
|
## Additional information
|