aboutsummaryrefslogtreecommitdiffstats
path: root/guides
diff options
context:
space:
mode:
authorStefan Wienert <info@stefanwienert.de>2018-04-23 13:30:47 +0200
committerStefan Wienert <info@stefanwienert.de>2018-04-28 20:48:13 +0200
commit4212470d2098678e970f600492f10f78037fca09 (patch)
treee7eb694623572d445473fafaddfd7cc4e40032c1 /guides
parentc991ebbc91ffaabf7452bd6364604dd524fc569d (diff)
downloadrails-4212470d2098678e970f600492f10f78037fca09.tar.gz
rails-4212470d2098678e970f600492f10f78037fca09.tar.bz2
rails-4212470d2098678e970f600492f10f78037fca09.zip
[ci skip] update ActiveStorage documentation
- added documentation on how to download files, with example of ActiveStorage::Downloading - documentation about linking files outside of controller/view - added section about DirectUpload JavaScript integration into libraries/frameworks, as well as usage in combination with Drag and Drop
Diffstat (limited to 'guides')
-rw-r--r--guides/source/active_storage_overview.md172
1 files changed, 172 insertions, 0 deletions
diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md
index d67f65e88a..b188597b8b 100644
--- a/guides/source/active_storage_overview.md
+++ b/guides/source/active_storage_overview.md
@@ -299,6 +299,30 @@ Call `images.attached?` to determine whether a particular message has any images
@message.images.attached?
```
+### Attaching File/IO Objects
+
+Sometimes you need to attach a file that doesn’t arrive via an HTTP request.
+For example, you may want to attach a file you generated on disk or downloaded
+from a user-submitted URL. You may also want to attach a fixture file in a
+model test. To do that, provide a Hash containing at least an open IO object
+and a filename:
+
+```ruby
+@message.image.attach(io: File.open('/path/to/file'), filename: 'file.pdf')
+```
+
+When possible, provide a content type as well. Active Storage attempts to
+determine a file’s content type from its data. It falls back to the content
+type you provide if it can’t do that.
+
+```ruby
+@message.image.attach(io: File.open('/path/to/file'), filename: 'file.pdf', content_type: 'application/pdf')
+```
+
+If you don’t provide a content type and Active Storage can’t determine the
+file’s content type automatically, it defaults to application/octet-stream.
+
+
Removing Files
--------------
@@ -334,6 +358,68 @@ helper allows you to set the disposition.
rails_blob_path(user.avatar, disposition: "attachment")
```
+If you need to create a link from outside of controller/view context (Background
+jobs, Cronjobs, etc.), you can access the rails_blob_path like this:
+
+```
+Rails.application.routes.url_helpers.rails_blob_path(user.avatar, only_path: true)
+```
+
+Downloading Files
+-----------------
+
+If you need to process the blobs on the server side, such as, when performing
+analysis or further conversions, you can download the blob and get a binary
+object:
+
+```ruby
+binary = user.avatar.download
+```
+
+In some cases you might want to convert that into an actual file on the disk to
+pass the file path to external programs (such as virus scanners, converters,
+optimizers, minifiers, etc.). In this case you can include the
+`ActiveStorage::Downloading` module into your class which provides helpers to
+download directly into files while avoiding to store the file into memory.
+`ActiveStorage::Downloading` expects a `blob` method to be defined.
+
+```ruby
+class VirusScanner
+ include ActiveStorage::Downloading
+
+ attr_reader :blob
+
+ def initialize(blob)
+ @blob = blob
+ end
+
+ def scan
+ download_blob_to_tempfile do |file|
+ system 'scan_virus', file.path
+ end
+ end
+end
+```
+
+By default, `download_blob_to_tempfile` creates files in `Dir.tmpdir`. If you need to use another directory, override ActiveStorage::Downloading#tempdir in your class:
+
+```ruby
+class VirusScanner
+ include ActiveStorage::Downloading
+ # ...
+
+ private
+ def tempdir
+ '/path/to/tmp'
+ end
+end
+```
+
+If the external program is run as a separate program, you might also want to
+chmod the file and it's directory, as it is unaccessible by other users because
+Tempfile will set the permissions to 0600.
+
+
Transforming Images
-------------------
@@ -516,6 +602,92 @@ input[type=file][data-direct-upload-url][disabled] {
}
```
+### Integrating with Libraries or Frameworks
+
+If you want to use the Direct Upload feature from a JavaScript framework, or
+you want to integrate custom drag and drop solutions, you can use the
+`DirectUpload` class for this purpose. Upon receiving a file from your library
+of choice, instantiate a DirectUpload and call its create method. Create takes
+a callback to invoke when the upload completes.
+
+```js
+import { DirectUpload } from "activestorage"
+
+const input = document.querySelector('input[type=file]')
+
+// Bind to file drop - use the ondrop on a parent element or use a
+// library like Dropzone
+const onDrop = (event) => {
+ event.preventDefault()
+ const files = event.dataTransfer.files;
+ Array.from(files).forEach(file => uploadFile(file))
+}
+
+// Bind to normal file selection
+input.addEventListener('change', (event) => {
+ Array.from(input.files).forEach(file => uploadFile(file))
+ // you might clear the selected files from the input
+ input.value = null
+})
+
+const uploadFile = (file) {
+ // your form needs the file_field direct_upload: true, which
+ // provides data-direct-upload-url
+ const url = input.dataset.directUploadUrl
+ const upload = new DirectUpload(file, url)
+
+ upload.create((error, blob) => {
+ if (error) {
+ // Handle the error
+ } else {
+ // Add an appropriately-named hidden input to the form with a
+ // value of blob.signed_id so that the blob ids will be
+ // transmitted in the normal upload flow
+ const hiddenField = document.createElement('input')
+ hiddenField.setAttribute("type", "hidden");
+ hiddenField.setAttribute("value", blob.signed_id);
+ hiddenField.name = input.name
+ document.querySelector('form').appendChild(hiddenField)
+ }
+ })
+}
+```
+
+If you need to track the progress of the file upload, you can pass a third
+parameter to the `DirectUpload` constructor. During the upload, DirectUpload
+will call the object's `directUploadWillStoreFileWithXHR` method. You can then
+bind your own progress handler on the XHR.
+
+```js
+import { DirectUpload } from "activestorage"
+
+class Uploader {
+ constructor(file, url) {
+ this.upload = new DirectUpload(this.file, this.url, this)
+ }
+
+ upload(file) {
+ this.upload.create((error, blob) => {
+ if (error) {
+ // Handle the error
+ } else {
+ // Add an appropriately-named hidden input to the form
+ // with a value of blob.signed_id
+ }
+ })
+ }
+
+ directUploadWillStoreFileWithXHR(request) {
+ request.upload.addEventListener("progress",
+ event => this.directUploadDidProgress(event))
+ }
+
+ directUploadDidProgress(event) {
+ // Use event.loaded and event.total to update the progress bar
+ }
+}
+```
+
Discarding Files Stored During System Tests
-------------------------------------------