Documentation
¶
Index ¶
- Variables
- func ContentTypeForFilename(name string) string
- func DetectContentType(data []byte, name string) string
- type Attachment
- type Blob
- func (b *Blob) DirectUpload(expiresIn time.Duration) (DirectUpload, error)
- func (b *Blob) Download() ([]byte, error)
- func (b *Blob) DownloadChunk(offset, length int64) ([]byte, error)
- func (b *Blob) Open(fn func(*os.File) error) error
- func (b *Blob) Purge() error
- func (b *Blob) Service() (Service, error)
- func (b *Blob) SignedID() (string, error)
- func (b *Blob) URL(opts URLOptions) (string, error)
- func (b *Blob) Upload(r io.Reader) error
- func (b *Blob) Variant(transformations Hash) *Variant
- type BlobParams
- type Config
- func (c *Config) BuildAfterUpload(r io.Reader, p BlobParams) (*Blob, error)
- func (c *Config) CreateAndUpload(r io.Reader, p BlobParams) (*Blob, error)
- func (c *Config) CreateBeforeDirectUpload(p BlobParams) (*Blob, error)
- func (c *Config) CreateForDirectUpload(p BlobParams, expiresIn time.Duration) (*Blob, DirectUpload, error)
- func (c *Config) FindBlob(id int64) (*Blob, error)
- func (c *Config) FindSignedBlob(signedID string) (*Blob, error)
- func (c *Config) Many(record RecordRef, name string) *ManyAttached
- func (c *Config) One(record RecordRef, name string) *OneAttached
- type DirectUpload
- type DirectUploadOptions
- type DirectUploadService
- type DiskService
- func (d *DiskService) Delete(key string) error
- func (d *DiskService) Download(key string) (io.ReadCloser, error)
- func (d *DiskService) DownloadChunk(key string, offset, length int64) ([]byte, error)
- func (d *DiskService) Exist(key string) (bool, error)
- func (d *DiskService) HeadersForDirectUpload(_ string, contentType string) map[string]string
- func (d *DiskService) Name() string
- func (d *DiskService) Root() string
- func (d *DiskService) Size(key string) (int64, error)
- func (d *DiskService) URLForDirectUpload(key string, o DirectUploadOptions) (string, error)
- func (d *DiskService) Upload(key string, r io.Reader, checksum string) error
- func (d *DiskService) Url(key string, opts URLOptions) (string, error)
- type Entry
- type Filename
- type HMACSigner
- type Hash
- type ManyAttached
- func (m *ManyAttached) Attach(attachables ...any) ([]*Attachment, error)
- func (m *ManyAttached) Attached() (bool, error)
- func (m *ManyAttached) Attachments() ([]*Attachment, error)
- func (m *ManyAttached) Blobs() ([]*Blob, error)
- func (m *ManyAttached) Detach() error
- func (m *ManyAttached) Purge() error
- type MemStore
- func (m *MemStore) DeleteAttachment(id int64) error
- func (m *MemStore) DeleteBlob(id int64) error
- func (m *MemStore) FindAttachments(recordType string, recordID int64, name string) ([]*Attachment, error)
- func (m *MemStore) FindBlob(id int64) (*Blob, error)
- func (m *MemStore) InsertAttachment(a *Attachment) error
- func (m *MemStore) InsertBlob(b *Blob) error
- func (m *MemStore) UpdateBlob(b *Blob) error
- type ModelStore
- type OneAttached
- type RailsVerifier
- func (v *RailsVerifier) Generate(value any, purpose string, expiresAt time.Time) (string, error)
- func (v *RailsVerifier) Sign(data, purpose string) (string, error)
- func (v *RailsVerifier) Verified(token, purpose string) ([]byte, error)
- func (v *RailsVerifier) Verify(token, purpose string) (string, error)
- type RandomSource
- type RecordRef
- type Registry
- type Service
- type Signer
- type Symbol
- type Transformer
- type URLOptions
- type Upload
- type Variant
- type VariantRecord
- type Variation
- type Verifier
Constants ¶
This section is empty.
Variables ¶
var ( // ErrIntegrity is returned when an uploaded object's checksum does not match // the expected value (Rails' ActiveStorage::IntegrityError). ErrIntegrity = errors.New("activestorage: integrity check failed") // ErrServiceNotFound is returned by a Registry when a named service (or the // default) is not configured. ErrServiceNotFound = errors.New("activestorage: service not registered") // ErrNotDirectUploadable is returned when a direct upload is requested from a // service that does not implement DirectUploadService. ErrNotDirectUploadable = errors.New("activestorage: service does not support direct uploads") )
Service-layer sentinel errors.
var ( ErrBlobNotFound = errors.New("activestorage: blob not found") ErrAttachmentNotFound = errors.New("activestorage: attachment not found") )
ErrBlobNotFound and ErrAttachmentNotFound are the sentinel errors a ModelStore returns when a lookup or mutation targets a row that does not exist.
var ErrExpired = errors.New("activestorage: signed message has expired")
ErrExpired is returned by a Verifier when a token carried an expiry that has already passed (ActiveSupport::MessageVerifier::InvalidSignature on expiry).
var ErrInvalidSignature = errors.New("activestorage: invalid signature")
ErrInvalidSignature is returned by a Signer.Verify when a token is malformed, tampered with, or signed for a different purpose.
var ErrNotTransformable = errors.New("activestorage: no image transformer configured")
ErrNotTransformable is returned when a variant's bytes are requested on a Config whose Transformer seam is unset. Producing variant bytes needs a real image processor (go-images, libvips, ImageMagick); the descriptor records — a variant's key, digest, filename, and content type — never do.
var ErrUnattachable = errors.New("activestorage: value is not attachable")
ErrUnattachable is returned when a value passed to Attach is not something the library knows how to turn into a Blob.
Functions ¶
func ContentTypeForFilename ¶
ContentTypeForFilename infers a MIME type from a filename's extension, dropping any parameters (e.g. "; charset=utf-8") to return a bare "type/subtype". When the extension is missing or unknown it returns application/octet-stream, the same conservative default Rails applies when content-type detection fails.
func DetectContentType ¶
DetectContentType reproduces ActiveStorage's extract_content_type, which is Marcel::MimeType.for(io, name:) for the common cases: it prefers the type implied by the leading magic bytes, upgrades a generic magic type to a more specific one implied by the name (xml→svg, zip→docx, …), and, when no magic matches, falls back to the name's extension — returning application/octet-stream only when neither yields anything.
Types ¶
type Attachment ¶
type Attachment struct {
ID int64
RecordType string
RecordID int64
Name string
BlobID int64
CreatedAt time.Time
// contains filtered or unexported fields
}
Attachment is the join record binding a blob to a named association on a record — ActiveStorage::Attachment (record, name, blob).
func (*Attachment) Blob ¶
func (a *Attachment) Blob() (*Blob, error)
Blob loads the attached blob, caching it on the attachment.
func (*Attachment) Purge ¶
func (a *Attachment) Purge() error
Purge deletes the attachment record and purges its blob — ActiveStorage::Attachment#purge.
type Blob ¶
type Blob struct {
ID int64
Key string
Filename string
ContentType string
Metadata map[string]any
ByteSize int64
Checksum string
ServiceName string
CreatedAt time.Time
// contains filtered or unexported fields
}
Blob is the persisted description of an uploaded file: where it lives (Key, ServiceName), what it is (Filename, ContentType, Metadata), and how to verify it (ByteSize, Checksum). It mirrors ActiveStorage::Blob's stored columns. The underlying database row is managed through the Config's ModelStore seam.
func (*Blob) DirectUpload ¶
func (b *Blob) DirectUpload(expiresIn time.Duration) (DirectUpload, error)
DirectUpload returns the signed URL, headers, and signed id a client needs to upload the blob's bytes directly to its service — ActiveStorage's service_url_for_direct_upload / service_headers_for_direct_upload / signed_id. It requires the blob's service to implement DirectUploadService.
func (*Blob) DownloadChunk ¶
DownloadChunk returns length bytes of the blob starting at offset.
func (*Blob) Open ¶
Open downloads the blob to a temporary file, verifies its checksum, and yields the open file positioned at the start. The temp file is always closed before it is removed, so the cleanup is safe on Windows (where an open file cannot be deleted). Mirrors ActiveStorage::Blob#open.
func (*Blob) Purge ¶
Purge deletes the blob's stored object and its database row — ActiveStorage::Blob#purge. Variant/attachment cascade purging is deferred (see the roadmap).
func (*Blob) SignedID ¶
SignedID returns a tamper-evident, purpose-scoped id for the blob, suitable for embedding in a URL — ActiveStorage::Blob#signed_id. With a RailsVerifier the token is byte-identical to the gem's (the integer id, purpose "blob_id", message-verifier envelope); with a plain Signer the id is signed as a string.
func (*Blob) URL ¶
func (b *Blob) URL(opts URLOptions) (string, error)
URL returns a service URL for the blob, defaulting the filename, content type, and disposition from the blob when the options leave them unset.
type BlobParams ¶
type BlobParams struct {
Filename string
ContentType string
Metadata map[string]any
ServiceName string
Key string
ByteSize int64
Checksum string
// Identify forces content-type detection from the uploaded bytes even when
// ContentType is set, mirroring Active Storage's identify: true default. When
// false, a caller-supplied ContentType is trusted (identify: false).
Identify bool
}
BlobParams describes a blob to build. Key and ContentType are derived when empty (a fresh base36 key; a MIME type inferred from Filename). ByteSize and Checksum are set automatically by the upload helpers, or supplied directly for a direct-upload blob.
type Config ¶
type Config struct {
Store ModelStore
Services *Registry
Signer Signer
Random RandomSource // defaults to DefaultRandom() when nil
Clock func() time.Time // defaults to time.Now().UTC when nil
Transformer Transformer // image-processing seam for variants; nil = variants unprocessable
}
Config bundles the pluggable seams the model logic depends on: the persistence store (ActiveRecord), the service registry, the signer (signed ids), the randomness source (storage keys), and a clock. It is the entry point for creating and finding blobs and attachments.
func (*Config) BuildAfterUpload ¶
BuildAfterUpload builds a blob from r and params and uploads it, but does not persist the row — ActiveStorage::Blob.build_after_upload.
func (*Config) CreateAndUpload ¶
CreateAndUpload builds a blob from r and params, persists the row, then uploads the bytes to the blob's service — ActiveStorage::Blob.create_and_upload!.
func (*Config) CreateBeforeDirectUpload ¶
func (c *Config) CreateBeforeDirectUpload(p BlobParams) (*Blob, error)
CreateBeforeDirectUpload builds and persists a blob from params (whose ByteSize and Checksum are already known) without uploading any bytes — the client will PUT them directly. Mirrors ActiveStorage::Blob.create_before_direct_upload!.
func (*Config) CreateForDirectUpload ¶
func (c *Config) CreateForDirectUpload(p BlobParams, expiresIn time.Duration) (*Blob, DirectUpload, error)
CreateForDirectUpload persists a blob from params (whose ByteSize and Checksum the client precomputed) and returns it alongside the DirectUpload payload the client uses to PUT the bytes and later attach the blob — the response shape of ActiveStorage::DirectUploadsController#create. expiresIn bounds the signed URL.
func (*Config) FindSignedBlob ¶
FindSignedBlob verifies a signed id and loads the blob it names. When the configured Signer is a Verifier (RailsVerifier), the id is decoded from the message-verifier payload (a JSON integer); otherwise the string Signer path is used.
type DirectUpload ¶
DirectUpload is the payload a client needs to upload straight to the service and then attach the blob — the shape ActiveStorage::DirectUploadsController returns: the blob's SignedID plus the upload URL and the required headers.
type DirectUploadOptions ¶
type DirectUploadOptions struct {
ContentType string
ContentLength int64
Checksum string
ExpiresIn time.Duration
}
DirectUploadOptions carries the blob facts a service embeds in a signed direct-upload token — the content type, length, and checksum the client must match, and how long the URL stays valid.
type DirectUploadService ¶
type DirectUploadService interface {
URLForDirectUpload(key string, opts DirectUploadOptions) (string, error)
HeadersForDirectUpload(key, contentType string) map[string]string
}
DirectUploadService is the optional capability of a Service that can mint a signed direct-upload URL and the headers a client must send with its PUT, mirroring ActiveStorage::Service#url_for_direct_upload and #headers_for_direct_upload.
type DiskService ¶
type DiskService struct {
// Verifier signs direct-upload tokens; nil disables DirectUploadService.
Verifier Verifier
// URLPrefix is prepended to a direct-upload token; defaults to
// "/rails/active_storage/disk/" when empty.
URLPrefix string
// Clock supplies "now" for token expiry; defaults to time.Now.
Clock func() time.Time
// contains filtered or unexported fields
}
DiskService is the built-in local-filesystem Service. It stores each object at Root/<key[0:2]>/<key[2:4]>/<key>, the same two-level sharding Rails' ActiveStorage::Service::DiskService uses to keep directories shallow.
When Verifier and URLPrefix are set it also mints signed direct-upload tokens (DirectUploadService) the same way ActiveStorage::Service::DiskService does.
func NewDiskService ¶
func NewDiskService(name, root string) *DiskService
NewDiskService returns a DiskService rooted at root and registered as name.
func (*DiskService) Delete ¶
func (d *DiskService) Delete(key string) error
Delete removes the object under key. A missing key is not an error (idempotent, like Rails rescuing Errno::ENOENT).
func (*DiskService) Download ¶
func (d *DiskService) Download(key string) (io.ReadCloser, error)
Download opens the object stored under key for reading. The caller closes it.
func (*DiskService) DownloadChunk ¶
func (d *DiskService) DownloadChunk(key string, offset, length int64) ([]byte, error)
DownloadChunk returns length bytes of the object under key starting at offset.
func (*DiskService) Exist ¶
func (d *DiskService) Exist(key string) (bool, error)
Exist reports whether an object is stored under key.
func (*DiskService) HeadersForDirectUpload ¶
func (d *DiskService) HeadersForDirectUpload(_ string, contentType string) map[string]string
HeadersForDirectUpload returns the headers a client must send with a direct upload — just the Content-Type, as ActiveStorage::Service::DiskService does.
func (*DiskService) Name ¶
func (d *DiskService) Name() string
Name returns the service's registry name.
func (*DiskService) Root ¶
func (d *DiskService) Root() string
Root returns the directory under which objects are stored.
func (*DiskService) Size ¶
func (d *DiskService) Size(key string) (int64, error)
Size returns the stored byte size of the object under key.
func (*DiskService) URLForDirectUpload ¶
func (d *DiskService) URLForDirectUpload(key string, o DirectUploadOptions) (string, error)
URLForDirectUpload returns a signed URL a client can PUT bytes to, embedding a message-verifier token over {key, content_type, content_length, checksum, service_name} scoped to purpose :blob_token — matching ActiveStorage::Service::DiskService#url_for_direct_upload.
func (*DiskService) Upload ¶
Upload writes r under key, creating the sharded directory as needed and, when checksum is non-empty, verifying the stored bytes' base64 MD5 against it (deleting the file and returning ErrIntegrity on mismatch).
func (*DiskService) Url ¶
func (d *DiskService) Url(key string, opts URLOptions) (string, error)
Url returns a disk-service URL for key. Without the Rails routing/engine layer (deferred, see the roadmap) this is a representative, disposition-annotated path rather than a signed, routable URL.
type Entry ¶
Entry is one key/value pair of an ordered Ruby hash. The key is a Symbol name (Active Storage deep-symbolizes transformation keys and builds its message-verifier payloads with symbol keys). Value is one of: int, int64, string, Symbol, bool, nil, []any, or Hash.
type Filename ¶
type Filename struct {
// contains filtered or unexported fields
}
Filename is a value type mirroring ActiveStorage::Filename: it exposes a file's base name, extension, and a sanitized form safe to persist or serve.
func (Filename) Base ¶
Base returns the basename with its extension removed (ActiveStorage::Filename#base).
func (Filename) Extension ¶
Extension returns the extension without its leading dot (e.g. "pdf"), or "".
func (Filename) ExtensionWithDelimiter ¶
ExtensionWithDelimiter returns the extension including its leading dot (e.g. ".pdf"), or "" when there is none.
type HMACSigner ¶
type HMACSigner struct {
Secret []byte
}
HMACSigner is the default Signer: it authenticates a payload with HMAC-SHA256 and encodes the token as "purpose.base64url(data).base64url(mac)". It is not a drop-in for Rails' exact wire format (that is a MessageVerifier concern), but it is a complete, self-contained default for standalone use.
func NewHMACSigner ¶
func NewHMACSigner(secret []byte) *HMACSigner
NewHMACSigner returns an HMACSigner keyed by secret.
type Hash ¶
type Hash []Entry
Hash is an ordered Ruby hash with symbol keys. Order is significant: it is the insertion order Ruby preserves, which fixes the byte layout of both JSON.dump and Marshal.dump (and hence a signed key or a variation digest). It is used for variation transformations and for message-verifier payloads.
type ManyAttached ¶
type ManyAttached struct {
// contains filtered or unexported fields
}
ManyAttached models a has_many_attached association: an ordered set of named attachments on a record.
func (*ManyAttached) Attach ¶
func (m *ManyAttached) Attach(attachables ...any) ([]*Attachment, error)
Attach appends each attachable to the record, returning the new attachments. On the first failure it returns the attachments created so far and the error.
func (*ManyAttached) Attached ¶
func (m *ManyAttached) Attached() (bool, error)
Attached reports whether at least one attachment is present.
func (*ManyAttached) Attachments ¶
func (m *ManyAttached) Attachments() ([]*Attachment, error)
Attachments returns the current attachments in insertion order.
func (*ManyAttached) Blobs ¶
func (m *ManyAttached) Blobs() ([]*Blob, error)
Blobs returns the attached blobs in order.
func (*ManyAttached) Detach ¶
func (m *ManyAttached) Detach() error
Detach removes all attachment records, leaving their blobs in place.
func (*ManyAttached) Purge ¶
func (m *ManyAttached) Purge() error
Purge removes all attachment records and purges their blobs.
type MemStore ¶
type MemStore struct {
// contains filtered or unexported fields
}
MemStore is a goroutine-safe, in-memory ModelStore. It is the reference implementation used in tests and suitable for the rbgo binding's scratch use; it is not durable.
func (*MemStore) DeleteAttachment ¶
DeleteAttachment removes the attachment with the given id, or returns ErrAttachmentNotFound.
func (*MemStore) DeleteBlob ¶
DeleteBlob removes the blob with the given id, or returns ErrBlobNotFound.
func (*MemStore) FindAttachments ¶
func (m *MemStore) FindAttachments(recordType string, recordID int64, name string) ([]*Attachment, error)
FindAttachments returns the attachments for a record and name, in insertion order.
func (*MemStore) InsertAttachment ¶
func (m *MemStore) InsertAttachment(a *Attachment) error
InsertAttachment assigns a.ID and stores the attachment.
func (*MemStore) InsertBlob ¶
InsertBlob assigns b.ID and stores the blob.
func (*MemStore) UpdateBlob ¶
UpdateBlob replaces the stored blob with the given id, or returns ErrBlobNotFound.
type ModelStore ¶
type ModelStore interface {
InsertBlob(b *Blob) error
FindBlob(id int64) (*Blob, error)
UpdateBlob(b *Blob) error
DeleteBlob(id int64) error
InsertAttachment(a *Attachment) error
FindAttachments(recordType string, recordID int64, name string) ([]*Attachment, error)
DeleteAttachment(id int64) error
}
ModelStore is the persistence seam. In Rails, Blob and Attachment are ActiveRecord models backed by the active_storage_blobs and active_storage_attachments tables; this interface abstracts that away so the model logic here has no database dependency. A host binds it to ActiveRecord (or any datastore); NewMemStore provides an in-memory reference implementation.
Insert* assigns the row's ID field. Find/Update/Delete operate by ID.
type OneAttached ¶
type OneAttached struct {
// contains filtered or unexported fields
}
OneAttached models a has_one_attached association: a single, named attachment on a record.
func (*OneAttached) Attach ¶
func (o *OneAttached) Attach(attachable any) (*Attachment, error)
Attach binds attachable to the record, replacing any existing attachment (the previous join record is removed). It returns the new attachment.
func (*OneAttached) Attached ¶
func (o *OneAttached) Attached() (bool, error)
Attached reports whether an attachment is present.
func (*OneAttached) Attachment ¶
func (o *OneAttached) Attachment() (*Attachment, error)
Attachment returns the current attachment, or nil when none is attached. If several rows exist (from prior attaches), the most recent wins.
func (*OneAttached) Blob ¶
func (o *OneAttached) Blob() (*Blob, error)
Blob returns the attached blob, or nil when none is attached.
func (*OneAttached) Detach ¶
func (o *OneAttached) Detach() error
Detach removes the attachment record, leaving its blob in place — ActiveStorage's detach.
func (*OneAttached) Purge ¶
func (o *OneAttached) Purge() error
Purge removes the attachment record and purges its blob.
type RailsVerifier ¶
type RailsVerifier struct {
Secret []byte
URLSafe bool // url-safe Base64 payload (Rails' message_verifier default)
Now func() time.Time // clock for expiry checks; defaults to time.Now
}
RailsVerifier reproduces ActiveSupport::MessageVerifier byte-for-byte for the serializer Rails uses by default (JSON) with a SHA-1 HMAC. Tokens have the wire form "<payload>--<hex-hmac>", where <payload> is url-safe (or strict) Base64 of either the bare serialized value or, when a purpose or expiry is present, the {"_rails":{"message":…,"exp":…,"pur":…}} metadata envelope. It implements both Signer (for string payloads) and Verifier (for typed payloads), so it can be a drop-in Config.Signer that makes blob signed_ids and variation keys match a running Rails app configured with the same secret.
func NewRailsVerifier ¶
func NewRailsVerifier(secret []byte) *RailsVerifier
NewRailsVerifier returns a RailsVerifier keyed by secret, using the url-safe Base64 encoding Rails' application message verifier uses.
func (*RailsVerifier) Sign ¶
func (v *RailsVerifier) Sign(data, purpose string) (string, error)
Sign implements Signer by treating data as a string value (Rails serializes it as a JSON string). For typed payloads use Generate.
type RandomSource ¶
type RandomSource interface {
// RandomBytes returns n cryptographically random bytes.
RandomBytes(n int) ([]byte, error)
// RandomNumber returns a uniform integer in [0, max).
RandomNumber(max int) (int, error)
}
RandomSource is the randomness seam. The default implementation is backed by crypto/rand; tests (and deterministic hosts) can inject their own. It mirrors the two primitives Ruby's SecureRandom.base36 relies on: random_bytes and random_number.
func DefaultRandom ¶
func DefaultRandom() RandomSource
DefaultRandom returns the crypto/rand-backed RandomSource used when a Config leaves Random unset.
type RecordRef ¶
RecordRef identifies the owning record of an attachment by its polymorphic type and id — the record_type / record_id columns of active_storage_attachments.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds the configured services and the default one (Rails config.active_storage.service). It is the resolver a Blob uses to turn its service_name into a Service.
func (*Registry) Default ¶
Default returns the default service, or ErrServiceNotFound if none is set.
func (*Registry) Register ¶
Register adds s under its Name(). If no default is set yet, the first registered service becomes the default. It returns the Registry for chaining.
func (*Registry) SetDefault ¶
SetDefault marks name as the default service.
type Service ¶
type Service interface {
// Name returns the service's registry name.
Name() string
// Upload stores r under key, verifying the base64 MD5 checksum when non-empty.
Upload(key string, r io.Reader, checksum string) error
// Download opens the object stored under key for reading.
Download(key string) (io.ReadCloser, error)
// DownloadChunk returns length bytes starting at offset.
DownloadChunk(key string, offset, length int64) ([]byte, error)
// Delete removes the object under key; missing keys are not an error.
Delete(key string) error
// Exist reports whether an object is stored under key.
Exist(key string) (bool, error)
// Url returns a URL from which the object can be retrieved.
Url(key string, opts URLOptions) (string, error)
// Size returns the stored byte size of the object under key.
Size(key string) (int64, error)
}
Service is the storage-backend seam. DiskService is the built-in local implementation. The interface is deliberately key-addressed and streaming — upload/download take a key and an io stream, ranged reads go through DownloadChunk, and URLs are minted from a key — so cloud services (S3, GCS, Azure, a mirror service) can implement the same contract without leaking any filesystem assumptions.
type Signer ¶
type Signer interface {
Sign(data, purpose string) (string, error)
Verify(token, purpose string) (string, error)
}
Signer is the message-signing seam. In Rails a blob's signed_id is produced by ActiveSupport::MessageVerifier; hosts can plug their own verifier here so signed ids interoperate with an existing application. The purpose argument scopes a token (ActiveStorage uses "blob_id") so a token minted for one purpose cannot be replayed for another.
type Symbol ¶
type Symbol string
Symbol marks a value that is a Ruby Symbol (e.g. a variation's :format value or :gravity argument), as distinct from a String. The distinction is invisible in JSON — both encode to a JSON string — but it changes the bytes of a Marshal.dump, and therefore a variation's digest, so it is preserved here.
type Transformer ¶
type Transformer interface {
// Transform applies transformations to the image in src, encoding the result
// as format (e.g. "png", "jpg"), and writes it to dst.
Transform(dst io.Writer, src io.Reader, transformations Hash, format string) error
}
Transformer is the image-processing seam. Active Storage delegates the actual pixel work to ImageProcessing (libvips / ImageMagick); this library keeps that out of the CGO-free core and lets a host inject a transformer (e.g. one backed by go-images). A variation's descriptor — its key, digest, filename, and content type — is computed without ever calling this.
type URLOptions ¶
type URLOptions struct {
ExpiresIn time.Duration
Filename Filename
ContentType string
Disposition string // "inline" or "attachment"
}
URLOptions carries the keyword options Rails passes to Service#url — how long a generated URL stays valid, and the Content-Disposition/type the download should present.
type Upload ¶
Upload is an attachable wrapping an io stream plus its filename and content type — the Rails { io:, filename:, content_type: } attachable form. Attaching one creates and uploads a new blob.
type Variant ¶
type Variant struct {
// contains filtered or unexported fields
}
Variant is a specific transformation of an image blob — ActiveStorage::Variant. Its Key locates the transformed object on the service; producing the bytes needs a Transformer.
func (*Variant) ContentType ¶
ContentType returns the variant's content type (its variation's output type).
func (*Variant) Filename ¶
Filename returns the variant's filename — the blob's base name with the variation's (downcased) format as extension, per ActiveStorage::Variant#filename.
func (*Variant) Key ¶
Key returns the variant's combined service key — "variants/<blob.key>/<SHA-256 hexdigest of the variation key>", matching ActiveStorage::Variant#key.
func (*Variant) Process ¶
Process downloads the blob, runs the configured Transformer over it, and uploads the transformed bytes under the variant's key — the work ActiveStorage::Variant#process performs. It returns ErrNotTransformable when no Transformer is configured. The digest/key descriptor records never require this.
type VariantRecord ¶
VariantRecord mirrors ActiveStorage::VariantRecord — the row that tracks a materialized variant of a blob by its variation digest, pointing (through an attachment named "image") at the variant's own stored blob.
func NewVariantRecord ¶
func NewVariantRecord(blobID int64, variation *Variation) (*VariantRecord, error)
NewVariantRecord builds the tracking record for variation on blobID, computing the variation digest the way Active Storage does.
type Variation ¶
type Variation struct {
Transformations Hash
// contains filtered or unexported fields
}
Variation is a set of image transformations that, applied to a blob, yields a variant — ActiveStorage::Variation. The transformations are an ordered Hash (Active Storage deep-symbolizes them); order is preserved because it fixes the bytes of both the signed key and the Marshal-based digest.
func NewVariation ¶
NewVariation builds a Variation from transformations, signed by v (needed for Key; Digest does not use it).
func (*Variation) ContentType ¶
ContentType returns the MIME type of the variation's output format, matching ActiveStorage::Variation#content_type (Marcel::MimeType.for(extension: format)).
func (*Variation) Digest ¶
Digest returns the variation's digest — the value stored in active_storage_variant_records.variation_digest to look a variant up. It is OpenSSL::Digest::SHA1.base64digest(Marshal.dump(transformations)), reproduced byte-for-byte via the internal Ruby-Marshal encoder.
type Verifier ¶
type Verifier interface {
// Generate returns a signed token binding value to purpose, optionally
// expiring at expiresAt (pass the zero time for no expiry).
Generate(value any, purpose string, expiresAt time.Time) (string, error)
// Verified checks a token's signature, purpose, and expiry, and returns the
// serialized (JSON) form of the original value.
Verified(token, purpose string) ([]byte, error)
}
Verifier is the message-verifier seam for the parts of Active Storage whose payloads are typed values rather than opaque strings — a blob's signed_id (an integer id), a variation key (a transformations Hash), and the disk service's direct-upload/blob-key tokens (an ordered Hash). It mirrors ActiveSupport::MessageVerifier#generate / #verified with a purpose and an optional expiry, serializing the value the way Rails does. A Signer that also implements Verifier (RailsVerifier does) is used through this richer interface where a byte-exact wire format matters.
