-
Accept Tempfile as
ActiveStorageattachable.tempfile = Tempfile.open(["users", ".csv"]) write_csv_to(tempfile) export.csv.attach(tempfile)Shouichi Kamiya
-
Require image processing backend upfront when Active Storage is being loaded.
This removes extra overhead when processing first variant after deploy and improves copy-on-write for preforking web servers.
Janko Marohnić
-
ActiveStorageProxyController now set relevantLast-ModifiedIt is now set to
Blob#created_atinstead of being hardcoded to January 1st 2011.Jean Boussier
-
Preserve attachment changes when converting record to another class using STI.
fatkodima
-
Add a helper to get the combined byte size of blobs attached via
has_many_attached.document.images.byte_size # => 2048Sandip Mane, fatkodima
-
Implement
attach!as a bang counterpart toattach.This method raises an exception if the attachment was not saved, similar to how
save!raises an exception if an Active Record object is found to be invalid prior to be persisted.Quentin de Metz
-
Correct unexpected behavior resulting from dependent:
:purgewhen using has_one_attached or has_many_attached. Fixes #36423.Mark Oveson
-
Allow configuring Active Storage base controller parent class
This enables users to change the parent class for
ActiveStorage::BaseController, including the option to inherit from::ActionController::APIfor api-only apps.Andrew White, Santiago Bartesaghi, zzak
-
Fix image analyzer reporting wrong dimensions for EXIF orientations involving a mirror.
rotated_image?was swapping width/height for orientations 2 and 4 (flip-only, no 90° rotation), which do not change portrait/landscape orientation. It was also missing orientations 5 and 7 (flip + 90° rotation), which do require a swap. Only orientations 5, 6, 7, and 8 involve a 90° or 270° rotation and should trigger a dimension swap.Bogdan Gusiev
-
Define
as_jsonon::ActiveStorage::Attached::Oneand::ActiveStorage::Attached::Many.The proxies hold a back-reference to the owning record in
@record. Without an explicitas_json, the default Object#as_json fall back serializedinstance_values, which maderecord.to_jsonrecurse infinitely whenever the attached name collided with a model attribute (e.g. anignored_columnscolumn brought back byselect('*')).Attached::One#as_jsonnow returns the attachment record's JSON when attached andnilotherwise.Attached::Many#as_jsonreturns the attachment records' JSON as an array.Renxiang Cai
-
Configurable maximum streaming chunk size
Makes sure that byte ranges for blobs don't exceed 100mb by default. Content ranges that are too big can result in denial of service.
Gannon McGibbon
-
Prevent path traversal in
DiskService.DiskService#path_fornow raises anInvalidKeyErrorwhen passed keys with dot segments (".", ".."), or if the resolved path is outside the storage root directory.#path_foralso now consistently raisesInvalidKeyErrorif the key is invalid in any way, for example containing null bytes or having an incompatible encoding. Previously, the exception raised may have beenArgumentErrororEncoding::CompatibilityError.DiskControllernow explicitly rescuesInvalidKeyErrorwith appropriate HTTP status codes.Mike Dalessio
-
Prevent glob injection in
DiskService#delete_prefixed.Escape glob metacharacters in the resolved path before passing to
Dir.glob.Note that this change breaks any existing code that is relying on
delete_prefixedto expand glob metacharacters. This change presumes that is unintended behavior (as other storage services do not respect these metacharacters).Mike Dalessio
-
Restore ADC when signing URLs with IAM for GCS
ADC was previously used for automatic authorization when signing URLs with IAM. Now it is again, but the auth client is memoized so that new credentials are only requested when the current ones expire. Other auth methods can now be used instead by setting the authorization on ActiveStorage::Service::GCSService#iam_client.
ActiveStorage::Blob.service.iam_client. = Google::Auth::ImpersonatedServiceAccountCredentials.new()This is safer than setting
Google::Apis::RequestOptions.default.authorizationbecause it only applies to Active Storage and does not affect other Google API clients.Justin Malčić
-
Move responsibility for checksums storage service
The storage service should implement calculating and validating checksums.
Matt Pasquini
-
Analyze attachments before validation
Attachment metadata (width, height, duration, etc.) is now available for model validations:
class User < ApplicationRecord has_one_attached :avatar validate :validate_avatar_dimensions, if: -> { avatar.attached? } def validate_avatar_dimensions if avatar.[:width] < 200 || avatar.[:height] < 200 errors.add(:avatar, "must be at least 200x200") end end endConfigure when analysis is performed:
analyze: :immediately(default in 8.2) - Analyze before validationanalyze: :later- Analyze after upload from local IO or via background jobanalyze: :lazily- Skip automatic analysis; analyze on-demand
has_one_attached :document, analyze: :later has_many_attached :files, analyze: :lazily # Or set the global default: config.active_storage.analyze = :laterDirect uploads bypass the server so the file isn't locally available for analysis. In this case,
:immediatelyfalls back to:later, analyzing via background job after upload completes. Metadata isn't available for validation; validate on the client side instead.Jeremy Daer
-
Use local files for immediate variant processing and analysis
process: :immediatelyvariants and blob analysis use local files directly instead of re-downloading after upload.Applies when attaching uploadable io, not when attaching an existing Blob.
Jeremy Daer
-
Introduce
ActiveStorage::Attachmentupload callbacksafter_uploadfires after an attachment's blob is uploaded, enabling analysis and processing to run deterministically rather than assuming after-commit callback execution ordering.ActiveStorage::Attachment.after_upload do # Your custom logic here endJeremy Daer
-
Introduce immediate variants that are generated immediately on attachment
The new
processoption determines when variants are created::lazily(default) - Variants are created dynamically when requested:later(replacespreprocessed: true) - Variants are created after attachment, in a background job:immediately(new) - Variants are created along with the attachment
has_one_attached :avatar do |attachable| attachable.variant :thumb, resize_to_limit: [100, 100], process: :immediately endThe
preprocessed: trueoption is deprecated in favor ofprocess: :later.Tom Rossi
-
Make
Variant#processed?andVariantWithRecord#processed?public so apps can check variant generation status.Tom Rossi
-
ActiveStorage::Blob#opencan now be used without passing a block, likeTempfile.open. When using this form the returned temporary file must be unlinked manually.Bart de Water
Please check [8-1-stable]) for previous changes.