From 3d6d9f077fe998292f25ec9753c52cd37e22d71d Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 2 Nov 2017 16:52:42 -0700 Subject: Begins guide for ActiveStorage --- guides/source/active_storage_overview.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 guides/source/active_storage_overview.md diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md new file mode 100644 index 0000000000..922a502502 --- /dev/null +++ b/guides/source/active_storage_overview.md @@ -0,0 +1,21 @@ +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** + +Active Storage +============== + +This guide covers how to attach files to your ActiveRecord models. + +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 implement a download link. +* How to approach implementing a custom service. + +-------------------------------------------------------------------------------- + +... general discussion of how things are meant to work.... + +Attaching Files to a Model +-------------------------- -- cgit v1.2.3 From 2def806f077e00297cf9d18c80ffee24592f9330 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 2 Nov 2017 16:52:54 -0700 Subject: Fixes typo in docs --- activestorage/lib/active_storage/service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activestorage/lib/active_storage/service.rb b/activestorage/lib/active_storage/service.rb index aa150e4d8a..343e5587d5 100644 --- a/activestorage/lib/active_storage/service.rb +++ b/activestorage/lib/active_storage/service.rb @@ -92,7 +92,7 @@ module ActiveStorage # Returns a signed, temporary URL that a direct upload file can be PUT to on the +key+. # The URL will be valid for the amount of seconds specified in +expires_in+. - # You most also provide the +content_type+, +content_length+, and +checksum+ of the file + # You must also provide the +content_type+, +content_length+, and +checksum+ of the file # that will be uploaded. All these attributes will be validated by the service upon upload. def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:) raise NotImplementedError -- cgit v1.2.3 From 142424334bc7be815e7911a0c3849f4d776c2c9c Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 9 Nov 2017 08:24:39 -0800 Subject: Adds todo for preview --- guides/source/active_storage_overview.md | 1 + 1 file changed, 1 insertion(+) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 922a502502..5300a2111f 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -10,6 +10,7 @@ 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 implement a download link. * How to approach implementing a custom service. -- cgit v1.2.3 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 +
    + <% @message.files.each do |file| %> +
  • + <%= image_tag file.preview(resize: "100x100>") %> +
  • + <% end %> +
+``` + +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 From a4298a7f8f26db2c59217a56e0405078eb1cb671 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 16 Nov 2017 19:07:10 -0800 Subject: Adds more explanation to points and add setup section --- guides/source/active_storage_overview.md | 75 +++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index afbc071f60..862f8e4410 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -15,6 +15,7 @@ After reading this guide, you will know: * How to upload files directly to a service. * How to implement a download link. * How to add support for additional cloud services. +* How to clean up files stored during testing. -------------------------------------------------------------------------------- @@ -51,8 +52,37 @@ 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). + +## Setup + +To setup an existing application after upgrading to Rails 5.2, run `rails active_storage:install`. If you're creating a new project with Rails 5.2, ActiveStorage will be installed by default. This generates the tables for the +`Attachment` and `Blob` models. + +Inside a Rails application, you can set-up your services through the +generated `config/storage.yml` file and reference one +of the aforementioned constant under the +service+ key. For example: + +``` yaml + local: + service: Disk + root: <%= Rails.root.join("storage") %> +``` +NOTE: Should we include the required keys for all the supported services? +NOTE: Should we mention the mirror service and how to set it up? + +In your application's configuration, specify the service to +use like this: + +``` ruby +config.active_storage.service = :local +``` + +Like other configuration options, you can set this application wide, or per +environment. + Attach Files to a Model -------------------------- +One or more files can be attached to a model. One attachment: @@ -115,6 +145,9 @@ end Remove File Attached to Model ------------------------------- +To remove an attachment from a model, call `purge` on the attachment. Removal +can be done in the background if your application is setup to use ActiveJob. + ```ruby # Synchronously destroy the avatar and actual resource files. user.avatar.purge @@ -125,25 +158,37 @@ user.avatar.purge_later Link to Attachments ---------------------- + +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. + ```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 ----------------------------------- +Sometimes your application will require images in a different format than +what was uploaded. To create variation of the image, call `variant` on the Blob. +You can pass any [MiniMagick](https://github.com/minimagick/minimagick) +supported transformation. + +When the browser hits the variant URL, ActiveStorage will lazy transform the +original blob into the format you specified and redirect to its new service +location. + ```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 ------------------------------------ +Previews can be generated from some non-image formats. ActiveStorage supports +Previewers for videos and PDFs. ```erb
    @@ -195,8 +240,26 @@ directly from the client to the cloud. | `direct-upload:end` | `` | `{id, file}` | A direct upload has ended. | | `direct-uploads:end` | `` | None | All direct uploads have ended. | +NOTE: Is there more to using the direct upload than this? How does one associate +the result with the form submission, or does that happen automatically? + Implement Direct Download Link ------------------------------ +TODO + Add Support Additional Cloud Service ------------------------------------ + +ActiveStorage ships with support for Amazon S3, Google Cloud Storage, and Azure. +If you need to support a cloud service other these, you will need to implement +the Service. Each service extends +[`ActiveStorage::Service`](https://github.com/rails/rails/blob/master/activestorage/lib/active_storage/service.rb) +by implementing the methods necessary to upload and download files to the cloud. + +The easiest way to understand what's necessary is to examine the existing +implementations. + +Some services are supported by community maintained gems: + +* [OpenStack](https://github.com/jeffreyguenther/activestorage-openstack) -- cgit v1.2.3 From 01c9f1363cf99076802dddc6b7e01cc1cf6032c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 16 Nov 2017 19:20:31 -0800 Subject: Adds testing section --- guides/source/active_storage_overview.md | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 862f8e4410..9c0d3d2709 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -77,8 +77,9 @@ use like this: config.active_storage.service = :local ``` -Like other configuration options, you can set this application wide, or per -environment. +Like other configuration options, you can set the service application wide, or per +environment. For example, you might want development and test to use the Disk +service instead of a cloud service. Attach Files to a Model -------------------------- @@ -248,6 +249,45 @@ Implement Direct Download Link TODO +Clean up Stored Files Store During System Tests +----------------------------------------------- + +System tests clean up test data by rolling back a transaction. Because destroy +is never called on an object, the attached files are never cleaned up. If you +want to clear the files, you can do it in an `after_teardown` callback. Doing it +here ensures that all connections to created during the test are complete and +you won't get an error from ActiveStorage saying it can't find a file. + +``` ruby +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] + + def remove_uploaded_files + FileUtils.rm_rf("#{Rails.root}/storage_test") + end + + def after_teardown + super + remove_uploaded_files + end +end +``` + +If your system tests verify the deletion of a model with attachments and your +using ActiveJob, set your test environment to use the inline queue adapter so +the purge job is executed immediately rather at an unknown time in the future. + +You may also want to use a separate service definition for the test environment +so your tests don't delete the files you create during development. + +``` ruby +# Use inline job processing to make things happen immediately +config.active_job.queue_adapter = :inline + +# Separate file storage in the test environment +config.active_storage.service = :local_test +``` + Add Support Additional Cloud Service ------------------------------------ -- cgit v1.2.3 From 6aac8fa3ec355f304d235f2e5a14a852584b6f02 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Sat, 18 Nov 2017 17:24:37 -0800 Subject: Integrates George's suggestions - Describes how to setup each of the services in the `services.yml` - Integrates copy changes --- guides/source/active_storage_overview.md | 187 ++++++++++++++++++++++--------- 1 file changed, 135 insertions(+), 52 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 9c0d3d2709..04f0ccec99 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -3,83 +3,165 @@ Active Storage ============== -This guide covers how to attach files to your ActiveRecord models. +This guide covers how to attach files to your Active Record models. 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 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 add support for additional cloud services. +* How to attach one or many files to a record. +* How to delete an attached file. +* How to link to an attached file. +* How to use variants to transform images. +* How to generate an image representation of a non-image file, such as a PDF or a video. +* How to send file uploads directly from browsers to a storage service, + bypassing your application servers. +* How to implement support for additional storage services. * How to clean up files stored during testing. -------------------------------------------------------------------------------- -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. +What is Active Storage? +----------------------- -Files can be uploaded from the server to the cloud or directly from the client -to the cloud. +Active Storage facilitates uploading files to a cloud storage service like +Amazon S3, Google Cloud Storage, or Microsoft Azure Storage and attaching those +files to Active Record objects. It comes with a local disk-based service for +development and testing and supports mirroring files to subordinate services for +backups and migrations. -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. +Using Active Storage, an application can transform image uploads with +[ImageMagick](https://www.imagemagick.org), generate image representations of +non-image uploads like PDFs and videos, and extract metadata from arbitrary +files. -## Compared to other storage solutions +## Setup -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`. +To setup an existing application after upgrading to Rails 5.2, run `rails +active_storage:install`. If you're creating a new project with Rails 5.2, +ActiveStorage will be installed by default. Installation generates a migration +to add the tables needed to store attachments. -`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). +If you wish to transform your images, add `mini_magick` to your Gemfile: +``` ruby +gem 'mini_magick' +``` -## Setup +Inside a Rails application, you can set up your services through the generated +`config/storage.yml` file and reference one of the supported service types under +the `service` key. + +### Disk Service +To use the Disk service: + +``` yaml +local: + service: Disk + root: <%= Rails.root.join("storage") %> +``` + +### Amazon S3 Service + +To use Amazon S3: +``` yaml +local: + service: S3 + access_key_id: "" + secret_access_key: "" + region: "" + bucket: "" +``` +Also, add the S3 client gem to your Gemfile: + +``` ruby +gem "aws-sdk-s3", require: false +``` +### Microsoft Azure Storage Service + +To use Microsoft Azure Storage: + +``` yaml +local: + service: AzureStorage + path: "" + storage_account_name: "" + storage_access_key: "" + container: "" +``` + +Also, add the Microsoft Azure Storage client gem to your Gemfile: + +``` ruby +gem "azure-storage", require: false +``` + +### Google Cloud Storage Service + +To use Google Cloud Storage: + +``` yaml +local: + service: GCS + keyfile: { + type: "service_account", + project_id: "", + private_key_id: "", + private_key: "", + client_email: "", + client_id: "", + auth_uri: "https://accounts.google.com/o/oauth2/auth", + token_uri: "https://accounts.google.com/o/oauth2/token", + auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs", + client_x509_cert_url: "" + } + project: "" + bucket: "" +``` + +Also, add the S3 client gem to your Gemfile: + +``` ruby +gem "google-cloud-storage", "~> 1.3", require: false +``` -To setup an existing application after upgrading to Rails 5.2, run `rails active_storage:install`. If you're creating a new project with Rails 5.2, ActiveStorage will be installed by default. This generates the tables for the -`Attachment` and `Blob` models. +### Mirror Service -Inside a Rails application, you can set-up your services through the -generated `config/storage.yml` file and reference one -of the aforementioned constant under the +service+ key. For example: +You can keep multiple services in sync by defining a mirror service. When +a file is uploaded or deleted, it's done across all the mirrored services. +Define each of the services you'd like to use as described above and then define +a mirrored service which references them. ``` yaml - local: - service: Disk - root: <%= Rails.root.join("storage") %> +s3_west_coast: + service: S3 + access_key_id: "" + secret_access_key: "" + region: "" + bucket: "" + +s3_east_coast: + service: S3 + access_key_id: "" + secret_access_key: "" + region: "" + bucket: "" + +production: + service: Mirror + primary: s3_east_coast + mirrors: + - s3_west_coast ``` -NOTE: Should we include the required keys for all the supported services? -NOTE: Should we mention the mirror service and how to set it up? -In your application's configuration, specify the service to -use like this: +In your application's configuration, specify the service to use like this: ``` ruby config.active_storage.service = :local ``` -Like other configuration options, you can set the service application wide, or per -environment. For example, you might want development and test to use the Disk -service instead of a cloud service. +Like other configuration options, you can set the service application wide in +`application.rb`, or per environment in `config/environments/{environment}.rb`. +For example, you might want development and test to use the Disk service instead +of a cloud service. Attach Files to a Model -------------------------- @@ -148,6 +230,7 @@ Remove File Attached to Model To remove an attachment from a model, call `purge` on the attachment. Removal can be done in the background if your application is setup to use ActiveJob. +Purging deletes the blob and the file from the storage service. ```ruby # Synchronously destroy the avatar and actual resource files. -- cgit v1.2.3 From ed8b299ec02607aee63788915b41d2dab8b142ff Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Sat, 18 Nov 2017 17:30:26 -0800 Subject: Proofreading --- guides/source/active_storage_overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 04f0ccec99..c3262c85e0 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -338,8 +338,8 @@ Clean up Stored Files Store During System Tests System tests clean up test data by rolling back a transaction. Because destroy is never called on an object, the attached files are never cleaned up. If you want to clear the files, you can do it in an `after_teardown` callback. Doing it -here ensures that all connections to created during the test are complete and -you won't get an error from ActiveStorage saying it can't find a file. +here ensures that all connections created during the test are complete and +you won't receive an error from ActiveStorage saying it can't find a file. ``` ruby class ApplicationSystemTestCase < ActionDispatch::SystemTestCase -- cgit v1.2.3 From 686b3466bab78ca69eaab98d76cc489d84d5eb62 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Mon, 20 Nov 2017 17:01:00 -0800 Subject: Adds download link helper explanation --- guides/source/active_storage_overview.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index c3262c85e0..4b48d67e60 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -117,7 +117,7 @@ local: bucket: "" ``` -Also, add the S3 client gem to your Gemfile: +Also, add the Google Cloud Storage client gem to your Gemfile: ``` ruby gem "google-cloud-storage", "~> 1.3", require: false @@ -245,7 +245,7 @@ Link to Attachments 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 +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. @@ -253,6 +253,13 @@ HTTP expiration of 5 min. url_for(user.avatar) ``` +To create a download link, use the `rails_blob_{path|url}` helper. Using this +helper will allow you to set the filename and disposition. + +```ruby +rails_blob_path(user.avatar, disposition: "attachment", filename: "avatar.jpg") +``` + Create Variations of Attached Image ----------------------------------- -- cgit v1.2.3 From 3718093c8326e1dad2adb50f9d5c6795f7d8ecf5 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Mon, 20 Nov 2017 17:09:28 -0800 Subject: Updates direct download discussion --- guides/source/active_storage_overview.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 4b48d67e60..4b31281f80 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -257,7 +257,7 @@ To create a download link, use the `rails_blob_{path|url}` helper. Using this helper will allow you to set the filename and disposition. ```ruby -rails_blob_path(user.avatar, disposition: "attachment", filename: "avatar.jpg") +rails_blob_path(user.avatar, disposition: "attachment") ``` Create Variations of Attached Image @@ -334,11 +334,6 @@ directly from the client to the cloud. NOTE: Is there more to using the direct upload than this? How does one associate the result with the form submission, or does that happen automatically? -Implement Direct Download Link ------------------------------- - -TODO - Clean up Stored Files Store During System Tests ----------------------------------------------- -- cgit v1.2.3 From c8370dc765e556ea9c01981a304cb7176bac08f9 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Mon, 20 Nov 2017 17:52:07 -0800 Subject: Remove mention of filename from download --- guides/source/active_storage_overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 4b31281f80..9d7d09983f 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -254,7 +254,7 @@ url_for(user.avatar) ``` To create a download link, use the `rails_blob_{path|url}` helper. Using this -helper will allow you to set the filename and disposition. +helper will allow you to set disposition. ```ruby rails_blob_path(user.avatar, disposition: "attachment") -- cgit v1.2.3 From 32203e889c771cbbc3f0bd9212d4b8bf4dc7da3f Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Mon, 20 Nov 2017 18:11:04 -0800 Subject: Adds tools caveat for generating previews --- guides/source/active_storage_overview.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 9d7d09983f..e3f7861861 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -291,6 +291,12 @@ Previewers for videos and PDFs.
``` +WARNING: Extracting previews requires third-party applications, `ffmpeg` for +video and `mutool` for PDFs. These libraries are not provided by Rails. You must +install them yourself to use the built-in previewers. Before you install and use +third-party software, make sure you understand the licensing implications of +doing so. + Upload Directly to Service -------------------------- -- cgit v1.2.3 From 3afffebe215c54fff73d1023c7214c755f71ac6f Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Tue, 21 Nov 2017 10:27:02 -0800 Subject: Updates add multiple attachments example --- guides/source/active_storage_overview.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index e3f7861861..10ff3de453 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -214,14 +214,18 @@ class MessagesController < ApplicationController end def create - message = Message.create! params.require(:message).permit(:title, :content) - message.images.attach(params[:message][:images]) + message = Message.create!(message_params) redirect_to message end def show @message = Message.find(params[:id]) end + + private + def message_params + params.require(:message).permit(:title, :content, images: []) + end end ``` @@ -254,7 +258,7 @@ url_for(user.avatar) ``` To create a download link, use the `rails_blob_{path|url}` helper. Using this -helper will allow you to set disposition. +helper allows you to set the disposition. ```ruby rails_blob_path(user.avatar, disposition: "attachment") @@ -263,7 +267,7 @@ rails_blob_path(user.avatar, disposition: "attachment") Create Variations of Attached Image ----------------------------------- -Sometimes your application will require images in a different format than +Sometimes your application requires images in a different format than what was uploaded. To create variation of the image, call `variant` on the Blob. You can pass any [MiniMagick](https://github.com/minimagick/minimagick) supported transformation. -- cgit v1.2.3 From 89f8471237e4c2efd4279646f10fa59c9cd1c7c7 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Tue, 21 Nov 2017 10:29:41 -0800 Subject: Corrects Active Job spelling --- guides/source/active_storage_overview.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 10ff3de453..43862236c3 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -233,7 +233,7 @@ Remove File Attached to Model ------------------------------- To remove an attachment from a model, call `purge` on the attachment. Removal -can be done in the background if your application is setup to use ActiveJob. +can be done in the background if your application is setup to use Active Job. Purging deletes the blob and the file from the storage service. ```ruby @@ -369,7 +369,7 @@ end ``` If your system tests verify the deletion of a model with attachments and your -using ActiveJob, set your test environment to use the inline queue adapter so +using Active Job, set your test environment to use the inline queue adapter so the purge job is executed immediately rather at an unknown time in the future. You may also want to use a separate service definition for the test environment -- cgit v1.2.3 From 7fb7679e17543b015d92dc9367d9ea382c40e825 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Tue, 21 Nov 2017 10:40:05 -0800 Subject: Removes note --- guides/source/active_storage_overview.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 43862236c3..aee9877256 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -341,9 +341,6 @@ directly from the client to the cloud. | `direct-upload:end` | `` | `{id, file}` | A direct upload has ended. | | `direct-uploads:end` | `` | None | All direct uploads have ended. | -NOTE: Is there more to using the direct upload than this? How does one associate -the result with the form submission, or does that happen automatically? - Clean up Stored Files Store During System Tests ----------------------------------------------- -- cgit v1.2.3 From 3429ab14a6f2380f4bd924fe9d9ad2eb967ae62b Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 30 Nov 2017 08:42:04 -0800 Subject: First pass on incoporating George's feedback --- guides/source/active_storage_overview.md | 73 +++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index aee9877256..5bfa82361e 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -35,20 +35,58 @@ files. ## Setup -To setup an existing application after upgrading to Rails 5.2, run `rails -active_storage:install`. If you're creating a new project with Rails 5.2, -ActiveStorage will be installed by default. Installation generates a migration -to add the tables needed to store attachments. +Active Storage uses two tables in your application’s database named +`active_storage_blobs` and `active_storage_attachments`. After upgrading your +application to Rails 5.2, run `rails active_storage:install` to generate a +migration that creates these tables. Use `rails db:migrate` to run the +migration. -If you wish to transform your images, add `mini_magick` to your Gemfile: +You need not run `rails active_storage:install` in a new Rails 5.2 application: +the migration is generated automatically. -``` ruby -gem 'mini_magick' +Declare Active Storage services in `config/storage.yml`. For each service your +application uses, provide a name and the requisite configuration. The example +below declares three services named `local`, `test`, and `s3`: + +```yaml +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +s3: + service: S3 + access_key_id: "" + secret_access_key: "" +``` + +Tell Active Storage which service to use by setting +`Rails.application.config.active_storage.service`. Because each environment will +likely use a different service, it is recommended to do this on a +per-environment basis. To use the disk service from the previous example in the +development environment, you would add the following to +config/environments/development.rb: + +In your application's configuration, specify the service to use like this: + +```ruby +# Store files locally. +config.active_storage.service = :local +``` + +To use the s3 service in production, you add the following to +`config/environments/production.rb`: + +```ruby +# Store files in S3. +config.active_storage.service = :s3 ``` -Inside a Rails application, you can set up your services through the generated -`config/storage.yml` file and reference one of the supported service types under -the `service` key. +Continue reading for more information on the built-in service adapters (e.g. +`Disk` and `S3`) and the configuration they require. ### Disk Service To use the Disk service: @@ -63,7 +101,7 @@ local: To use Amazon S3: ``` yaml -local: +s3: service: S3 access_key_id: "" secret_access_key: "" @@ -80,7 +118,7 @@ gem "aws-sdk-s3", require: false To use Microsoft Azure Storage: ``` yaml -local: +azure: service: AzureStorage path: "" storage_account_name: "" @@ -99,7 +137,7 @@ gem "azure-storage", require: false To use Google Cloud Storage: ``` yaml -local: +google: service: GCS keyfile: { type: "service_account", @@ -152,17 +190,12 @@ production: - s3_west_coast ``` -In your application's configuration, specify the service to use like this: +If you wish to transform your images, add `mini_magick` to your Gemfile: ``` ruby -config.active_storage.service = :local +gem 'mini_magick' ``` -Like other configuration options, you can set the service application wide in -`application.rb`, or per environment in `config/environments/{environment}.rb`. -For example, you might want development and test to use the Disk service instead -of a cloud service. - Attach Files to a Model -------------------------- One or more files can be attached to a model. -- cgit v1.2.3 From 858e5cd09cc5b3f387ff358f51e87ab85feb0fb9 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 30 Nov 2017 09:01:01 -0800 Subject: Adds Javan's event example --- guides/source/active_storage_overview.md | 100 ++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 5bfa82361e..943df46d21 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -165,8 +165,8 @@ gem "google-cloud-storage", "~> 1.3", require: false You can keep multiple services in sync by defining a mirror service. When a file is uploaded or deleted, it's done across all the mirrored services. -Define each of the services you'd like to use as described above and then define -a mirrored service which references them. +Define each of the services you'd like to use as described above and reference +them from a mirrored service. ``` yaml s3_west_coast: @@ -190,6 +190,10 @@ production: - s3_west_coast ``` +Mirrored services can be used to facilitate a migration between services in +production. You can start mirroring to the new service, copy existing files from +the old service to the new, then go all-in on the new service. + If you wish to transform your images, add `mini_magick` to your Gemfile: ``` ruby @@ -374,6 +378,98 @@ directly from the client to the cloud. | `direct-upload:end` | `` | `{id, file}` | A direct upload has ended. | | `direct-uploads:end` | `` | None | All direct uploads have ended. | +### Example + +You can use these events to show the progress of an upload. + +![direct-uploads](https://user-images.githubusercontent.com/5355/28694528-16e69d0c-72f8-11e7-91a7-c0b8cfc90391.gif) + +To show the uploaded files in a form: +```js +// direct_uploads.js + +addEventListener("direct-upload:initialize", event => { + const { target, detail } = event + const { id, file } = detail + target.insertAdjacentHTML("beforebegin", ` +
+
+ ${file.name} +
+ `) +}) + +addEventListener("direct-upload:start", event => { + const { id } = event.detail + const element = document.getElementById(`direct-upload-${id}`) + element.classList.remove("direct-upload--pending") +}) + +addEventListener("direct-upload:progress", event => { + const { id, progress } = event.detail + const progressElement = document.getElementById(`direct-upload-progress-${id}`) + progressElement.style.width = `${progress}%` +}) + +addEventListener("direct-upload:error", event => { + event.preventDefault() + const { id, error } = event.detail + const element = document.getElementById(`direct-upload-${id}`) + element.classList.add("direct-upload--error") + element.setAttribute("title", error) +}) + +addEventListener("direct-upload:end", event => { + const { id } = event.detail + const element = document.getElementById(`direct-upload-${id}`) + element.classList.add("direct-upload--complete") +}) +``` + +Add styles: + +```css +/* direct_uploads.css */ + +.direct-upload { + display: inline-block; + position: relative; + padding: 2px 4px; + margin: 0 3px 3px 0; + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 3px; + font-size: 11px; + line-height: 13px; +} + +.direct-upload--pending { + opacity: 0.6; +} + +.direct-upload__progress { + position: absolute; + top: 0; + left: 0; + bottom: 0; + opacity: 0.2; + background: #0076ff; + transition: width 120ms ease-out, opacity 60ms 60ms ease-in; + transform: translate3d(0, 0, 0); +} + +.direct-upload--complete .direct-upload__progress { + opacity: 0.4; +} + +.direct-upload--error { + border-color: red; +} + +input[type=file][data-direct-upload-url][disabled] { + display: none; +} +``` + Clean up Stored Files Store During System Tests ----------------------------------------------- -- cgit v1.2.3 From 29051b60a26951ee71d9129a4eb5bc399f9a6cb0 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 30 Nov 2017 09:19:57 -0800 Subject: Change info to note --- guides/source/active_storage_overview.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 943df46d21..537a0e841d 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -190,6 +190,8 @@ production: - s3_west_coast ``` +NOTE: Files are served from the primary service. + Mirrored services can be used to facilitate a migration between services in production. You can start mirroring to the new service, copy existing files from the old service to the new, then go all-in on the new service. @@ -349,14 +351,19 @@ directly from the client to the cloud. 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 @@ -385,6 +392,7 @@ You can use these events to show the progress of an upload. ![direct-uploads](https://user-images.githubusercontent.com/5355/28694528-16e69d0c-72f8-11e7-91a7-c0b8cfc90391.gif) To show the uploaded files in a form: + ```js // direct_uploads.js @@ -426,7 +434,7 @@ addEventListener("direct-upload:end", event => { }) ``` -Add styles: +Add styles: ```css /* direct_uploads.css */ -- cgit v1.2.3 From 08fab27db52aa375df85a23e89799600f785b9d4 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Mon, 4 Dec 2017 20:56:16 -0800 Subject: Incorporate latest round of feedback --- guides/source/active_storage_overview.md | 124 +++++++++++++++++-------------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 537a0e841d..d28a67b150 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -70,8 +70,6 @@ per-environment basis. To use the disk service from the previous example in the development environment, you would add the following to config/environments/development.rb: -In your application's configuration, specify the service to use like this: - ```ruby # Store files locally. config.active_storage.service = :local @@ -88,8 +86,18 @@ config.active_storage.service = :s3 Continue reading for more information on the built-in service adapters (e.g. `Disk` and `S3`) and the configuration they require. +Mirrored services can be used to facilitate a migration between services in +production. You can start mirroring to the new service, copy existing files from +the old service to the new, then go all-in on the new service. + +If you wish to transform your images, add `mini_magick` to your Gemfile: + +``` ruby +gem 'mini_magick' +``` + ### Disk Service -To use the Disk service: +Declare a Disk service in `config/storage.yml`: ``` yaml local: @@ -98,8 +106,8 @@ local: ``` ### Amazon S3 Service +Declare an S3 service in `config/storage.yml`: -To use Amazon S3: ``` yaml s3: service: S3 @@ -114,8 +122,7 @@ Also, add the S3 client gem to your Gemfile: gem "aws-sdk-s3", require: false ``` ### Microsoft Azure Storage Service - -To use Microsoft Azure Storage: +Declare an Azure Storage service in `config/storage.yml`: ``` yaml azure: @@ -133,8 +140,7 @@ gem "azure-storage", require: false ``` ### Google Cloud Storage Service - -To use Google Cloud Storage: +Declare a Google Cloud Storage service in `config/storage.yml`: ``` yaml google: @@ -192,42 +198,59 @@ production: NOTE: Files are served from the primary service. -Mirrored services can be used to facilitate a migration between services in -production. You can start mirroring to the new service, copy existing files from -the old service to the new, then go all-in on the new service. - -If you wish to transform your images, add `mini_magick` to your Gemfile: - -``` ruby -gem 'mini_magick' -``` - Attach Files to a Model -------------------------- -One or more files can be attached to a model. -One attachment: +### `has_one_attached` -```ruby +The `has_one_attached` macro sets up a one-to-one mapping between records and +files. Each record can have one file attached to it. + +For example, suppose your application has a User model. If you want each user to +have an avatar, define the `User` model like this: + +``` 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") +You can create a user with an avatar: -class AvatarsController < ApplicationController - def update - # params[:avatar] contains a ActionDispatch::Http::UploadedFile object - Current.user.avatar.attach(params.require(:avatar)) - redirect_to Current.user +``` ruby +class SignupController < ApplicationController + def create + user = Users.create!(user_params) + session[:user_id] = user.id + redirect_to root_path end + + private + def user_params + params.require(:user).permit(:email_address, :password, :avatar) + end end ``` -Many attachments: +Call `avatar.attach` to attach an avatar to an existing user: + +```ruby +Current.user.avatar.attach(params[:avatar]) +``` + +Call `avatar.attached?` to determine whether a particular user has an avatar: + +```ruby +Current.user.avatar.attached? +``` + +### `has_many_attached` + +The `has_many_attached` macro sets up a one-to-many relationship between records +and files. Each record can have many files attached to it. + +For example, suppose your application has a `Message` model. If you want each +message to have many images, define the Message model like this: ```ruby class Message < ApplicationRecord @@ -235,32 +258,15 @@ class Message < ApplicationRecord 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 %> -``` +You can create a message with images: ```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!(message_params) redirect_to message end - def show - @message = Message.find(params[:id]) - end - private def message_params params.require(:message).permit(:title, :content, images: []) @@ -268,6 +274,18 @@ class MessagesController < ApplicationController end ``` +Call `images.attach` to add new images to an existing message: + +```ruby +@message.images.attach(params[:images]) +``` + +Call `images.attached?`` to determine whether a particular message has any images: + +```ruby +@message.images.attached? +``` + Remove File Attached to Model ------------------------------- @@ -520,15 +538,7 @@ config.active_storage.service = :local_test Add Support Additional Cloud Service ------------------------------------ -ActiveStorage ships with support for Amazon S3, Google Cloud Storage, and Azure. If you need to support a cloud service other these, you will need to implement the Service. Each service extends [`ActiveStorage::Service`](https://github.com/rails/rails/blob/master/activestorage/lib/active_storage/service.rb) by implementing the methods necessary to upload and download files to the cloud. - -The easiest way to understand what's necessary is to examine the existing -implementations. - -Some services are supported by community maintained gems: - -* [OpenStack](https://github.com/jeffreyguenther/activestorage-openstack) -- cgit v1.2.3 From ab2a95db8088b7607017671b82e396bcd9e80332 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Fri, 8 Dec 2017 13:44:59 -0800 Subject: Apply edits and suggestions --- guides/source/active_storage_overview.md | 39 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index d28a67b150..5027d3acf4 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -86,16 +86,6 @@ config.active_storage.service = :s3 Continue reading for more information on the built-in service adapters (e.g. `Disk` and `S3`) and the configuration they require. -Mirrored services can be used to facilitate a migration between services in -production. You can start mirroring to the new service, copy existing files from -the old service to the new, then go all-in on the new service. - -If you wish to transform your images, add `mini_magick` to your Gemfile: - -``` ruby -gem 'mini_magick' -``` - ### Disk Service Declare a Disk service in `config/storage.yml`: @@ -169,10 +159,13 @@ gem "google-cloud-storage", "~> 1.3", require: false ### Mirror Service -You can keep multiple services in sync by defining a mirror service. When -a file is uploaded or deleted, it's done across all the mirrored services. -Define each of the services you'd like to use as described above and reference -them from a mirrored service. +You can keep multiple services in sync by defining a mirror service. When a file +is uploaded or deleted, it's done across all the mirrored services. Mirrored +services can be used to facilitate a migration between services in production. +You can start mirroring to the new service, copy existing files from the old +service to the new, then go all-in on the new service. Define each of the +services you'd like to use as described above and reference them from a mirrored +service. ``` yaml s3_west_coast: @@ -280,7 +273,7 @@ Call `images.attach` to add new images to an existing message: @message.images.attach(params[:images]) ``` -Call `images.attached?`` to determine whether a particular message has any images: +Call `images.attached?` to determine whether a particular message has any images: ```ruby @message.images.attached? @@ -327,7 +320,13 @@ Create Variations of Attached Image Sometimes your application requires images in a different format than what was uploaded. To create variation of the image, call `variant` on the Blob. You can pass any [MiniMagick](https://github.com/minimagick/minimagick) -supported transformation. +supported transformation to the method. + +To enable variants, add `mini_magick` to your Gemfile: + +``` ruby +gem 'mini_magick' +``` When the browser hits the variant URL, ActiveStorage will lazy transform the original blob into the format you specified and redirect to its new service @@ -520,7 +519,7 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase end ``` -If your system tests verify the deletion of a model with attachments and your +If your system tests verify the deletion of a model with attachments and you're using Active Job, set your test environment to use the inline queue adapter so the purge job is executed immediately rather at an unknown time in the future. @@ -535,10 +534,10 @@ config.active_job.queue_adapter = :inline config.active_storage.service = :local_test ``` -Add Support Additional Cloud Service +Add Support for Additional Cloud Services ------------------------------------ -If you need to support a cloud service other these, you will need to implement -the Service. Each service extends +If you need to support a cloud service other than these, you will need to +implement the Service. Each service extends [`ActiveStorage::Service`](https://github.com/rails/rails/blob/master/activestorage/lib/active_storage/service.rb) by implementing the methods necessary to upload and download files to the cloud. -- cgit v1.2.3 From 1dba0a279df6806aff3dbd08d4ae6858e7d03f32 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 14 Dec 2017 19:08:33 -0800 Subject: Formatting updates --- guides/source/active_storage_overview.md | 33 ++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 5027d3acf4..28fe80658a 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -14,8 +14,8 @@ After reading this guide, you will know: * How to generate an image representation of a non-image file, such as a PDF or a video. * How to send file uploads directly from browsers to a storage service, bypassing your application servers. -* How to implement support for additional storage services. * How to clean up files stored during testing. +* How to implement support for additional storage services. -------------------------------------------------------------------------------- @@ -87,6 +87,7 @@ Continue reading for more information on the built-in service adapters (e.g. `Disk` and `S3`) and the configuration they require. ### Disk Service + Declare a Disk service in `config/storage.yml`: ``` yaml @@ -96,6 +97,7 @@ local: ``` ### Amazon S3 Service + Declare an S3 service in `config/storage.yml`: ``` yaml @@ -112,6 +114,7 @@ Also, add the S3 client gem to your Gemfile: gem "aws-sdk-s3", require: false ``` ### Microsoft Azure Storage Service + Declare an Azure Storage service in `config/storage.yml`: ``` yaml @@ -130,6 +133,7 @@ gem "azure-storage", require: false ``` ### Google Cloud Storage Service + Declare a Google Cloud Storage service in `config/storage.yml`: ``` yaml @@ -192,7 +196,7 @@ production: NOTE: Files are served from the primary service. Attach Files to a Model --------------------------- +----------------------- ### `has_one_attached` @@ -280,7 +284,7 @@ Call `images.attached?` to determine whether a particular message has any images ``` Remove File Attached to Model -------------------------------- +----------------------------- To remove an attachment from a model, call `purge` on the attachment. Removal can be done in the background if your application is setup to use Active Job. @@ -295,7 +299,7 @@ user.avatar.purge_later ``` Link to Attachments ----------------------- +------------------- 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 @@ -314,11 +318,10 @@ helper allows you to set the disposition. rails_blob_path(user.avatar, disposition: "attachment") ``` -Create Variations of Attached Image ------------------------------------ +Transform Images +---------------- -Sometimes your application requires images in a different format than -what was uploaded. To create variation of the image, call `variant` on the Blob. +To create variation of the image, call `variant` on the Blob. You can pass any [MiniMagick](https://github.com/minimagick/minimagick) supported transformation to the method. @@ -336,10 +339,12 @@ location. <%= image_tag user.avatar.variant(resize: "100x100") %> ``` -Create Image Previews of Attachments ------------------------------------- -Previews can be generated from some non-image formats. ActiveStorage supports -Previewers for videos and PDFs. +Preview Non-image Files +----------------------- + +Some non-image files can be previewed: that is, they can be presented as images. +For example, a video file can be previewed by extracting its first frame. Out of +the box, Active Storage supports previewing videos and PDF documents. ```erb
    @@ -534,8 +539,8 @@ config.active_job.queue_adapter = :inline config.active_storage.service = :local_test ``` -Add Support for Additional Cloud Services ------------------------------------- +Support Additional Cloud Services +--------------------------------- If you need to support a cloud service other than these, you will need to implement the Service. Each service extends -- cgit v1.2.3 From 53757939b727c63a77d179b07130430e27868dc0 Mon Sep 17 00:00:00 2001 From: Jeffrey Guenther Date: Thu, 14 Dec 2017 19:09:48 -0800 Subject: Tweak whitespace --- guides/source/active_storage_overview.md | 1 + 1 file changed, 1 insertion(+) diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md index 28fe80658a..2ab14ad3de 100644 --- a/guides/source/active_storage_overview.md +++ b/guides/source/active_storage_overview.md @@ -113,6 +113,7 @@ Also, add the S3 client gem to your Gemfile: ``` ruby gem "aws-sdk-s3", require: false ``` + ### Microsoft Azure Storage Service Declare an Azure Storage service in `config/storage.yml`: -- cgit v1.2.3