← Back to Issue

Allow config.active_storage.variant_processor to be set to a class

From uloza+hey@proton.me · original ↗ · unsubscribe

The class must implement the interface defined by ActiveStorage::Transformers::Transformer. Active Storage then uses it for variant processing


Allow `config.active_storage.variant_processor` to be set to a class by flavorjones · Pull Request #58384 · rails/rails · GitHub

Skip to content

Sign in

Appearance settings

Search/

Sign in

Sign up

Appearance settings

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert

Uh oh!

There was an error while loading. Please reload this page.

rails / rails Public

Additional navigation options

Allow config.active_storage.variant_processor to be set to a class - #58384

#58384

Merged

flavorjones merged 1 commit into

rails:mainrails/rails:mainfrom

flavorjones:variant-transformer-seamflavorjones/rails:variant-transformer-seamCopy head branch name to clipboard

Aug 7, 2026

ConversationCommits1 (1)ChecksFiles changed

Merged

##

Allow config.active_storage.variant_processor to be set to a class#58384

flavorjones merged 1 commit into

rails:mainrails/rails:mainfrom

flavorjones:variant-transformer-seamflavorjones/rails:variant-transformer-seamCopy head branch name to clipboard

Conversation

@flavorjones

###

@flavorjonesflavorjones commented Aug 5, 2026

Copy link

Copy Markdown

Member

Motivation / Background

Active Storage passes attachment bytes to a media library in three operations: analysis, preview generation, and variant processing. An application can replace the code for two of them: config.active_storage.analyzers and config.active_storage.previewers each accept an array of classes.

Variant processing has no equivalent. config.active_storage.variant_processor accepts only :vips, :mini_magick, and :disabled (though, note that ActiveStorage::Engine maps those symbols to a class):

ActiveStorage.variant_transformer = case ActiveStorage.variant_processor when :disabled ActiveStorage::Transformers::NullTransformer when :vips ActiveStorage::Transformers::Vips when :mini_magick ActiveStorage::Transformers::ImageMagick end

ActiveStorage.variant_transformer is an undocumented mattr_accessor, so an application cannot use it directly.

This gap makes it challenging to experiment with variant processors, for example to play around with sandboxing image transformations.

Detail

config.active_storage.variant_processor now accepts a class, in addition to :vips, :mini_magick, and :disabled. The class must implement the interface defined by ActiveStorage::Transformers::Transformer in order to behave properly, though that is not explicitly checked. Active Storage then uses it for variant processing.

config.active_storage.variant_processor = CustomTransformer

Note that the built-in image analyzers accept a blob only when variant_processor is :vips or :mini_magick, so setting this configuration to a custom class requires adding a custom analyzer to config.active_storage.analyzers as well (for now).

One notable change: an unrecognized value now raises ArgumentError while booting, instead of failing later with NoMethodError when a variant is generated. I think this is a good thing.

Additional information

This change only adds the abstraction layer. It does not add any custom or additional transformers.

Active Storage does not check the type of the configured class. The class does not have to subclass ActiveStorage::Transformers::Transformer. It only has to implement the same interface.

The allowlist for transformation names and arguments is in ActiveStorage::Transformers::ImageMagick, and ActiveStorage::Transformers::Vips does not apply it. I think that it’s worth moving that validation to the analyzer/transformer/previewer classes, but should be done in a separate PR.

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one change. Unrelated changes should be opened in separate PRs.
  • Commit message has a detailed description of what changed and why. If this PR fixes a related issue include it in the commit message. Ex: [Fix #issue-number]
  • Tests are added or updated if you fix a bug or add a feature.
  • CHANGELOG files are updated for the changed libraries if there is a behavior change or additional feature. Minor bug fixes and documentation changes should not be included.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions @github-actions github-actions Bot added railties docs activestorage labels Aug 5, 2026

@flavorjones

flavorjones requested a lite review from Copilot August 6, 2026 02:34

Copilot started reviewing on behalf of flavorjones August 6, 2026 02:35 View session

Copilot AI reviewed Aug 6, 2026

View reviewed changes

###

Copilot AI left a comment

Copy link

Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide comment

Pull request overview

This PR extends Active Storage’s configuration to allow config.active_storage.variant_processor to be set to a transformer class (in addition to the existing :vips, :mini_magick, and :disabled symbols), enabling applications to plug in custom variant processing implementations.

Changes:

  • Update Active Storage engine initialization to accept a class-based variant_processor and raise ArgumentError for unknown values during boot.
  • Add integration tests covering both the class-based configuration path and the new boot-time error behavior.
  • Document the new configuration option in the Guides, API docs, and the Active Storage changelog.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file

File

Description

activestorage/lib/active_storage/engine.rb

Accept transformer classes for variant_processor and raise early for unknown values.

railties/test/application/active_storage/engine_integration_test.rb

Adds coverage for class-based configuration and unknown-value error behavior.

railties/test/application/active_storage/custom_processors_integration_test.rb

New integration test demonstrating a custom analyzer + custom transformer end-to-end.

guides/source/configuring.md

Documents class-based variant_processor and notes analyzer implications.

activestorage/lib/active_storage/transformers/transformer.rb

Clarifies the custom transformer interface contract in documentation.

activestorage/app/models/active_storage/variant.rb

Updates public docs to reflect that only built-in transformers require image_processing.

activestorage/CHANGELOG.md

Adds changelog entry describing the new configuration behavior.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

Comment thread railties/test/application/active_storage/custom_processors_integration_test.rb Show resolved Hide resolved

Uh oh!

There was an error while loading. Please reload this page.

@flavorjones

flavorjones force-pushed the variant-transformer-seam branch from bb9fca0 to 05cb696 Compare August 6, 2026 02:44

@flavorjones

[Allow `config.active_storage.variant_processor` to be set to a class](/rails/rails/pull/58384/commits/54cbc21ce0ec848f77b3d3513e8e53de5eff864f "Allow `config.active_storage.variant_processor` to be set to a class Active Storage passes attachment bytes to a media library in three operations: analysis, preview generation, and variant processing. An application could replace the code for two of them, through `config.active_storage.analyzers` and `config.active_storage.previewers`. Variant processing had no equivalent. `config.active_storage.variant_processor` accepted only `:vips`, `:mini_magick`, and `:disabled`, and the engine assigned `ActiveStorage.variant_transformer` in `config.after_initialize`, so an application that set it in an initializer lost the value. That made it challenging to opt into experimental variant processing, for example to play around with sandboxing image transformations. `config.active_storage.variant_processor` will also accept a class, in addition to `:vips`, `:mini_magick`, and `:disabled`. The class must implement the interface defined by `ActiveStorage::Transformers::Transformer`. Active Storage will then use it for variant processing. Note that the built-in image analyzers accept a blob only when `variant_processor` is `:vips` or `:mini_magick`, so setting this configuration to a custom class will require adding a custom analyzer to `config.active_storage.analyzers` as well. An unrecognized value will raise `ArgumentError` while booting, instead of failing later with `NoMethodError` when a variant is generated.") …

[54cbc21](/rails/rails/pull/58384/commits/54cbc21ce0ec848f77b3d3513e8e53de5eff864f)

Active Storage passes attachment bytes to a media library in three operations: analysis, preview generation, and variant processing. An application could replace the code for two of them, through `config.active_storage.analyzers` and `config.active_storage.previewers`. Variant processing had no equivalent. `config.active_storage.variant_processor` accepted only `:vips`, `:mini_magick`, and `:disabled`, and the engine assigned `ActiveStorage.variant_transformer` in `config.after_initialize`, so an application that set it in an initializer lost the value. That made it challenging to opt into experimental variant processing, for example to play around with sandboxing image transformations.

`config.active_storage.variant_processor` will also accept a class, in addition to `:vips`, `:mini_magick`, and `:disabled`. The class must implement the interface defined by `ActiveStorage::Transformers::Transformer`. Active Storage will then use it for variant processing. Note that the built-in image analyzers accept a blob only when `variant_processor` is `:vips` or `:mini_magick`, so setting this configuration to a custom class will require adding a custom analyzer to `config.active_storage.analyzers` as well. An unrecognized value will raise `ArgumentError` while booting, instead of failing later with `NoMethodError` when a variant is generated.

@flavorjones

flavorjones force-pushed the variant-transformer-seam branch from 05cb696 to 54cbc21 Compare August 6, 2026 02:44

@flavorjones

flavorjones requested a review from jeremy August 7, 2026 19:17

@jeremy jeremy added this to the 8.2.0 milestone Aug 7, 2026

jeremy

jeremy approved these changes Aug 7, 2026

View reviewed changes

@flavorjones

###

flavorjones commented Aug 7, 2026

Copy link

Copy Markdown

Member Author

Note for posterity: I had a side chat with @jeremy about using straight class references here (and in the other existing config params config.active_storage.analyzers and config.active_storage.previewers) where he pointed out the “lumpy” conventions currently in use.

Specifically:

  • config.active_storage.variant_processor currently takes a snake case symbol, which might reasonably be expected to extend like config.session_store where the symbol is classified and resolved under a fixed namespace
  • but the analyzers and previewers are configured with a straight array of Class references
  • and that the use of Class references can defeat much of the boot-time ordering in Rails, resulting in early loads or failures to reload in development

So if this is merged I’ll plan to follow up with another PR that would add support for the following configuration conventions:

  • snake case symbol (classified and resolved under a documented namespace)
  • class name (resolved when needed, and at reload)
  • literal class references

across all three active storage processor config params.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Hide details View details

@flavorjones

flavorjones merged commit 5ea765e into rails:main Aug 7, 2026

5 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@julianrubisch julianrubisch mentioned this pull request Aug 8, 2026

Activestorage transformers for custom media types #58398

Open

4 tasks

@flavorjones flavorjones mentioned this pull request Aug 14, 2026

(saas-only) Process Active Storage attachments in a HotCell cell basecamp/fizzy#3034

Open

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

### Reviewers

Copilot code review Copilot

Copilot review effort Lite

  • Lite Efficient review, low cost
  • Balanced Deep analysis, moderate cost
  • Max Most thorough, high cost Coming soon

Applies to this pull request for everyone.Learn more about Copilot code review.

Copilot left review comments

@jeremyjeremy jeremy approved these changes

Assignees

No one assigned

Labels

activestorage docs railties

Projects

None yet

Milestone

8.2.0

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@flavorjones@jeremy

Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

© 2026 GitHub, Inc.

You can’t perform that action at this time.

Highlights & notes

    Notes