Extract ActiveStorage::Streaming so your own controllers can use it (#41440)

Extract ActiveStorage::Streaming so your own controller can use it
This commit is contained in:
David Heinemeier Hansson 2021-02-19 15:40:56 +01:00 committed by GitHub
parent ee7cf8cf75
commit ab8e3d22cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 42 additions and 32 deletions

View File

@ -89,9 +89,6 @@ Layout/EmptyLinesAroundModuleBody:
Style/HashSyntax:
Enabled: true
Layout/FirstArgumentIndentation:
Enabled: true
# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Layout/IndentationConsistency:

View File

@ -1,3 +1,20 @@
* Add `ActiveStorage::Streaming` module that can be included in a controller to get access to `#send_blob_stream`,
which wraps the new `ActionController::Base#send_stream` method to stream a blob from cloud storage:
```ruby
class MyPublicBlobsController < ApplicationController
include ActiveStorage::SetBlob, ActiveStorage::Streaming
def show
http_cache_forever(public: true) do
send_blob_stream @blob, disposition: params[:disposition]
end
end
end
```
*DHH*
* Add ability to use pre-defined variants.
```ruby

View File

@ -2,18 +2,9 @@
# The base class for all Active Storage controllers.
class ActiveStorage::BaseController < ActionController::Base
include ActiveStorage::SetCurrent
include ActiveStorage::SetCurrent, ActiveStorage::Streaming
protect_from_forgery with: :exception
self.etag_with_template_digest = false
private
def stream(blob)
blob.download do |chunk|
response.stream.write chunk
end
ensure
response.stream.close
end
end

View File

@ -3,12 +3,10 @@
# Proxy files through application. This avoids having a redirect and makes files easier to cache.
class ActiveStorage::Blobs::ProxyController < ActiveStorage::BaseController
include ActiveStorage::SetBlob
include ActiveStorage::SetHeaders
def show
http_cache_forever public: true do
set_content_headers_from @blob
stream @blob
send_blob_stream @blob
end
end
end

View File

@ -3,12 +3,10 @@
# Proxy files through application. This avoids having a redirect and makes files easier to cache.
class ActiveStorage::Representations::ProxyController < ActiveStorage::BaseController
include ActiveStorage::SetBlob
include ActiveStorage::SetHeaders
def show
http_cache_forever public: true do
set_content_headers_from representation.image
stream representation
send_blob_stream representation.image
end
end

View File

@ -1,12 +0,0 @@
# frozen_string_literal: true
module ActiveStorage::SetHeaders #:nodoc:
extend ActiveSupport::Concern
private
def set_content_headers_from(blob)
response.headers["Content-Type"] = blob.content_type_for_serving
response.headers["Content-Disposition"] = ActionDispatch::Http::ContentDisposition.format \
disposition: blob.forced_disposition_for_serving || params[:disposition] || "inline", filename: blob.filename.sanitized
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module ActiveStorage::Streaming
DEFAULT_BLOB_STREAMING_DISPOSITION = "inline"
include ActionController::Live
private
# Stream the blob from storage directly to the response. The disposition can be controlled by setting +disposition+.
# The content type and filename is set directly from the +blob+.
def send_blob_stream(blob, disposition: nil) #:doc:
send_stream(
filename: blob.filename.sanitized,
disposition: blob.forced_disposition_for_serving || disposition || DEFAULT_BLOB_STREAMING_DISPOSITION,
type: blob.content_type_for_serving) do |stream|
blob.download do |chunk|
stream.write chunk
end
end
end
end

View File

@ -48,7 +48,7 @@ class ActiveStorage::Representations::ProxyControllerWithPreviewsTest < ActionDi
assert_predicate @blob.preview_image, :attached?
image = read_image(@blob.preview_image.variant(resize: "100x100"))
image = read_image(@blob.preview_image.variant(resize: "100x100").processed)
assert_equal 77, image.width
assert_equal 100, image.height
end