Skip to content

Commit

Permalink
Extract ActiveStorage::Streaming so your own controllers can use it (#…
Browse files Browse the repository at this point in the history
…41440)

Extract ActiveStorage::Streaming so your own controller can use it
  • Loading branch information
dhh committed Feb 19, 2021
1 parent ee7cf8c commit ab8e3d2
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 32 deletions.
3 changes: 0 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
17 changes: 17 additions & 0 deletions activestorage/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
11 changes: 1 addition & 10 deletions activestorage/app/controllers/active_storage/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

This file was deleted.

21 changes: 21 additions & 0 deletions activestorage/app/controllers/concerns/active_storage/streaming.rb
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit ab8e3d2

Please sign in to comment.