From d58078d8d65de38d9dca9c629c91e13df291dbb3 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 9 Nov 2017 08:51:14 -0800 Subject: Adds content from README and conversations with George --- guides/source/active_storage_overview.md | 188 ++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 4 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 5300a2111f..afbc071f60 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -10,13 +10,193 @@ After reading this guide, you will know: * How to attach a file(s) to a model. * How to remove the attached file. * How to link to the attached file. -* How to generate a preview for files other than images +* How to create variations of an image. +* How to generate a preview for files other than images. +* How to upload files directly to a service. * How to implement a download link. -* How to approach implementing a custom service. +* How to add support for additional cloud services. -------------------------------------------------------------------------------- -... general discussion of how things are meant to work.... +Active Storage makes it simple to upload and reference files in cloud services +like Amazon S3, Google Cloud Storage, or Microsoft Azure Storage, and attach +those files to Active Records. Supports having one main service and mirrors in +other services for redundancy. It also provides a disk service for testing or +local deployments, but the focus is on cloud storage. -Attaching Files to a Model +Files can be uploaded from the server to the cloud or directly from the client +to the cloud. + +Image files can furthermore be transformed using on-demand variants for quality, +aspect ratio, size, or any other +[MiniMagick](https://github.com/minimagick/minimagick) supported transformation. + +## Compared to other storage solutions + +A key difference to how Active Storage works compared to other attachment +solutions in Rails is through the use of built-in +[Blob](https://github.com/rails/rails/blob/master/activestorage/app/models/active_storage/blob.rb) +and +[Attachment](https://github.com/rails/rails/blob/master/activestorage/app/models/active_storage/attachment.rb) +models (backed by Active Record). This means existing application models do not +need to be modified with additional columns to associate with files. Active +Storage uses polymorphic associations via the `Attachment` join model, which +then connects to the actual `Blob`. + +`Blob` models store attachment metadata (filename, content-type, etc.), and +their identifier key in the storage service. Blob models do not store the actual +binary data. They are intended to be immutable in spirit. One file, one blob. +You can associate the same blob with multiple application models as well. And if +you want to do transformations of a given `Blob`, the idea is that you'll simply +create a new one, rather than attempt to mutate the existing one (though of +course you can delete the previous version later if you don't need it). + +Attach Files to a Model -------------------------- + +One attachment: + +```ruby +class User < ApplicationRecord + # Associates an attachment and a blob. When the user is destroyed they are + # purged by default (models destroyed, and resource files deleted). + has_one_attached :avatar +end + +# Attach an avatar to the user. +user.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg") + +class AvatarsController < ApplicationController + def update + # params[:avatar] contains a ActionDispatch::Http::UploadedFile object + Current.user.avatar.attach(params.require(:avatar)) + redirect_to Current.user + end +end +``` + +Many attachments: + +```ruby +class Message < ApplicationRecord + has_many_attached :images +end +``` + +```erb +<%= form_with model: @message, local: true do |form| %> + <%= form.text_field :title, placeholder: "Title" %>
+ <%= form.text_area :content %>

+ + <%= form.file_field :images, multiple: true %>
+ <%= form.submit %> +<% end %> +``` + +```ruby +class MessagesController < ApplicationController + def index + # Use the built-in with_attached_images scope to avoid N+1 + @messages = Message.all.with_attached_images + end + + def create + message = Message.create! params.require(:message).permit(:title, :content) + message.images.attach(params[:message][:images]) + redirect_to message + end + + def show + @message = Message.find(params[:id]) + end +end +``` + +Remove File Attached to Model +------------------------------- + +```ruby +# Synchronously destroy the avatar and actual resource files. +user.avatar.purge + +# Destroy the associated models and actual resource files async, via Active Job. +user.avatar.purge_later +``` + +Link to Attachments +---------------------- +```ruby +# Generate a permanent URL for the blob that points to the application. +# Upon access, a redirect to the actual service endpoint is returned. +# This indirection decouples the public URL from the actual one, and +# allows for example mirroring attachments in different services for +# high-availability. The redirection has an HTTP expiration of 5 min. +url_for(user.avatar) +``` + +Create Variations of Attached Image +----------------------------------- + +```erb +<%# Hitting the variant URL will lazy transform the original blob and then redirect to its new service location %> +<%= image_tag user.avatar.variant(resize: "100x100") %> +``` + +Create Image Previews of Attachments +------------------------------------ + +```erb + +``` + +Upload Directly to Service +-------------------------- + +Active Storage, with its included JavaScript library, supports uploading +directly from the client to the cloud. + +### Direct upload installation + +1. Include `activestorage.js` in your application's JavaScript bundle. + + Using the asset pipeline: + ```js + //= require activestorage + ``` + Using the npm package: + ```js + import * as ActiveStorage from "activestorage" + ActiveStorage.start() + ``` +2. Annotate file inputs with the direct upload URL. + + ```ruby + <%= form.file_field :attachments, multiple: true, direct_upload: true %> + ``` +3. That's it! Uploads begin upon form submission. + +### Direct upload JavaScript events + +| Event name | Event target | Event data (`event.detail`) | Description | +| --- | --- | --- | --- | +| `direct-uploads:start` | `
` | None | A form containing files for direct upload fields was submitted. | +| `direct-upload:initialize` | `` | `{id, file}` | Dispatched for every file after form submission. | +| `direct-upload:start` | `` | `{id, file}` | A direct upload is starting. | +| `direct-upload:before-blob-request` | `` | `{id, file, xhr}` | Before making a request to your application for direct upload metadata. | +| `direct-upload:before-storage-request` | `` | `{id, file, xhr}` | Before making a request to store a file. | +| `direct-upload:progress` | `` | `{id, file, progress}` | As requests to store files progress. | +| `direct-upload:error` | `` | `{id, file, error}` | An error occurred. An `alert` will display unless this event is canceled. | +| `direct-upload:end` | `` | `{id, file}` | A direct upload has ended. | +| `direct-uploads:end` | `` | None | All direct uploads have ended. | + +Implement Direct Download Link +------------------------------ + +Add Support Additional Cloud Service +------------------------------------ -- cgit v1.2.3