Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Active storage add proxying #34477

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
170 commits
Select commit Hold shift + click to select a range
d0b1280
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Nov 3, 2018
177574f
Basic redirects and proxying is working on the model level.
fleck Nov 5, 2018
31a2d2a
Proxying variants is working.
fleck Nov 8, 2018
09f37c3
Fix preview.
fleck Nov 8, 2018
39eb31a
Working on previews.
fleck Nov 8, 2018
71b499e
Should fix errors with previews not streaming.
fleck Nov 14, 2018
7c00122
Move delivery logic to method.
fleck Nov 15, 2018
96b54a7
change delivery method default and add support for direct.
fleck Nov 17, 2018
0b488cc
Fix blob route.
fleck Nov 17, 2018
5281255
Accidentally removed blob resolver, re add it.
fleck Nov 17, 2018
4dd0e2f
Basic redirects and proxying is working on the model level.
fleck Nov 5, 2018
0db8f77
Proxying variants is working.
fleck Nov 8, 2018
813b8e0
Fix preview.
fleck Nov 8, 2018
ca72a7e
Working on previews.
fleck Nov 8, 2018
73f2202
Should fix errors with previews not streaming.
fleck Nov 14, 2018
8ee4bfb
Move delivery logic to method.
fleck Nov 15, 2018
3a1bc1d
change delivery method default and add support for direct.
fleck Nov 17, 2018
61d228d
Fix blob route.
fleck Nov 17, 2018
c82b288
Accidentally removed blob resolver, re add it.
fleck Nov 17, 2018
0f621c8
Merge branch 'active-storage-add-proxying-and-direct-downloads' of gi…
fleck Nov 17, 2018
9e34b40
Remove extra comment.
fleck Nov 17, 2018
25429de
Explain variant and preview.
fleck Nov 17, 2018
a55f88f
don't use 'its'
fleck Nov 17, 2018
f5586e2
Fix disposition and content type.
fleck Nov 17, 2018
f016113
Add delivery method to has_many_attached.
fleck Nov 17, 2018
46f110e
Get service_url from processed not blob.
fleck Nov 17, 2018
3ae4936
Fix code climate issues.
fleck Nov 17, 2018
464ed95
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Dec 4, 2018
2d2fb66
Add model instance method overrides.
fleck Dec 4, 2018
f0c7723
Fix code climate issues and give blob method path option.
fleck Dec 4, 2018
331ed77
Merge branch 'master' of https://github.com/rails/rails
fleck Dec 9, 2018
c271ee6
Merge branch 'master' of https://github.com/rails/rails
fleck Dec 16, 2018
9aed641
Merge branch 'master' of https://github.com/rails/rails
fleck Dec 24, 2018
e83edfb
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Dec 24, 2018
da1df76
Make proxied assets public.
fleck Dec 25, 2018
fe0ff8f
Add documentation.
fleck Dec 29, 2018
9676f88
Merge branch 'master' of https://github.com/rails/rails
fleck Dec 30, 2018
b31bb85
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Dec 30, 2018
97ebfaf
Added test for blobs controller to verify correct caching.
fleck Jan 1, 2019
969a1ed
Test representation proxy cache control headers.
fleck Jan 1, 2019
ec254dd
Test global proxying option.
fleck Jan 12, 2019
017e8ae
Add test for deliver method on blob.
fleck Jan 13, 2019
b932f1b
Test delivery on variants.
fleck Jan 13, 2019
80db667
Change range for comparison.
fleck Jan 13, 2019
7bfb8b2
Fixed bug with model delivery setting.
fleck Jan 14, 2019
3d76291
Update configuration test.
fleck Jan 14, 2019
66a4a20
Update routes test.
fleck Jan 14, 2019
93fbf27
Dry up routes.
fleck Jan 15, 2019
13ac0f4
Change parameter name.
fleck Jan 15, 2019
1483c17
Add tests for delivery method on model.
fleck Jan 15, 2019
6ef2c7e
Test preview methods.
fleck Jan 15, 2019
18deb51
Clean up delivery method test.
fleck Jan 15, 2019
24244d7
Add test for preview.
fleck Jan 15, 2019
0cea5a0
Merge branch 'master' of https://github.com/rails/rails
fleck Jan 15, 2019
ba02d81
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Jan 15, 2019
da0084c
Fix code climate issues.
fleck Jan 15, 2019
7056d6a
Fix routes_prefix railtie test.
fleck Jan 16, 2019
cec9b0d
Fixed rake routes railtie test.
fleck Jan 16, 2019
72edc1c
Redo backticks in test name.
fleck Jan 16, 2019
93808b7
Updating another routes test.
fleck Jan 16, 2019
ddbe958
Update last rails routes test.
fleck Jan 16, 2019
8ddfa55
Merge branch 'master' of https://github.com/rails/rails
fleck Mar 31, 2019
3d34726
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Mar 31, 2019
16e1641
Merge branch 'master' of https://github.com/rails/rails
fleck Mar 31, 2019
aa6cdf0
Merge branch 'master' of https://github.com/rails/rails
fleck Apr 7, 2019
69fa76a
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Apr 7, 2019
c53b4e6
Remove direct delivery method.
fleck Apr 7, 2019
7fb06f1
Remove tests for direct delivery.
fleck Apr 7, 2019
d6e69e9
Update attachments reflection test.
fleck Apr 7, 2019
a9b249a
Remove dependent reflection.
fleck Apr 7, 2019
a3c2882
Merge branch 'master' of https://github.com/rails/rails
fleck Apr 7, 2019
a335e3b
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Apr 7, 2019
e7979b6
Remove direct from overview.
fleck Apr 8, 2019
290453a
Merge branch 'master' of https://github.com/rails/rails
fleck Apr 27, 2019
4faafc0
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Apr 27, 2019
22645e7
Add support for changing host.
fleck May 13, 2019
1e758f3
Merge branch 'master' of https://github.com/rails/rails
fleck May 13, 2019
1abfd9a
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck May 13, 2019
1dc2188
Refactor logic out of routes and into class
fleck May 29, 2019
cc8d0c3
Fix code climate issues.
fleck May 29, 2019
486b0bc
Merge branch 'master' of https://github.com/rails/rails
fleck Jun 1, 2019
f84e086
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Jun 1, 2019
06693d4
Clean up some edge cases and add test.
fleck Jun 1, 2019
baa1929
Update docs.
fleck Jun 1, 2019
6ce1f1b
Clean up extra curly braces
fleck Jun 1, 2019
73639b8
Proxy delivery method is working
fleck Jul 27, 2019
64d6a28
Move url options method.
fleck Jul 29, 2019
86131e3
Merge branch 'master' of https://github.com/rails/rails
fleck Jul 29, 2019
7c23631
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Jul 29, 2019
7660a4f
code climate fixes.
fleck Jul 29, 2019
6c1d003
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Aug 3, 2019
21b29bc
Move URL options to each class.
fleck Aug 5, 2019
521244f
simply registering delivery method.
fleck Aug 19, 2019
eacde0f
Variants are working for has_one
fleck Aug 20, 2019
e772d75
Less nils
fleck Aug 20, 2019
d117ab9
Fix model level setting.
fleck Aug 22, 2019
302923a
Cleaning up tests to use .url
fleck Aug 22, 2019
fb397b2
Can't set cache control per instance
fleck Aug 22, 2019
acf951a
Fix expire time
fleck Aug 22, 2019
9b7ca2c
Merge branch 'master' into active-storage-add-proxying-and-direct-dow…
fleck Aug 30, 2019
71d8a2c
Split up config
fleck Oct 1, 2019
32d604c
Add docs for cdn.
fleck Oct 1, 2019
2f15573
Remove cloudflare from docs.
fleck Oct 1, 2019
f35423b
Clean up host docs.
fleck Oct 1, 2019
cc545d6
Updating overview.
fleck Oct 1, 2019
bcb5ffe
Update configuration.
fleck Oct 1, 2019
bdd0f80
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Oct 1, 2019
eb64ff0
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Oct 2, 2019
d09134c
Update docs and engine.
fleck Oct 16, 2019
c8c67ba
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Oct 16, 2019
68a36ad
Fix method name.
fleck Oct 16, 2019
5930a22
Fix config test.
fleck Oct 16, 2019
1938c82
Update to new method in tests.
fleck Oct 16, 2019
fbaaca9
days is more readable.
fleck Oct 21, 2019
68f9816
simplifying
fleck Nov 6, 2019
e717e69
Use days for proxy_urls_expire_in
fleck Nov 6, 2019
bd19891
Moving header logic to concern, removing extra delivery_methods
fleck Nov 6, 2019
1207c3c
Remove dup routes_prefix
fleck Nov 6, 2019
ba1f16f
Remove model delivery_method from test.
fleck Nov 6, 2019
7819297
set headers in concern.
fleck Nov 6, 2019
4accc9d
Cleanup routes.
fleck Nov 19, 2019
2003663
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Nov 19, 2019
f4044b8
Fix typo.
fleck Nov 28, 2019
f67a4bc
use same convention for routes.
fleck Nov 28, 2019
4bd8f5f
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Dec 16, 2019
1927754
move url call to the model.
fleck Dec 28, 2019
99386a3
Cleanup old implementation
fleck Dec 28, 2019
366ab0b
Remove extra settings.
fleck Dec 28, 2019
975571e
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Mar 11, 2020
2817a38
Remove methods from model.
fleck Mar 11, 2020
c07d9ad
Add direct route for proxy
fleck Mar 14, 2020
c9342c7
same API for blobs and representations
fleck Mar 15, 2020
dc84bdd
split routes
fleck Apr 1, 2020
a147010
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Apr 1, 2020
e698761
Set expire in controller.
fleck Apr 1, 2020
387baf3
Start cleaning up tests.
fleck Apr 1, 2020
c08951d
Allow custom resolve name
fleck Apr 8, 2020
293553d
Update docs.
fleck Apr 8, 2020
c8fc088
tweak
fleck Apr 8, 2020
108e344
Update config readme.
fleck Apr 8, 2020
e4eba43
typo
fleck Apr 8, 2020
491b4d5
Revert model test.
fleck Apr 8, 2020
b7cc8c7
Revert old test changes.
fleck Apr 8, 2020
6d732d2
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Apr 8, 2020
176edc7
Update expanded routes.
fleck Apr 8, 2020
3e79f37
Fix routes -g show
fleck Apr 8, 2020
69260a8
Fix another route test.
fleck Apr 8, 2020
7d2ad32
Update config test.
fleck Apr 8, 2020
b09f350
fix rake route test.
fleck Apr 8, 2020
ea0bda8
change config name
fleck Apr 9, 2020
9ff39ac
Update routes in test.
fleck Apr 9, 2020
2885507
Update form helper test.
fleck Apr 9, 2020
dec20c4
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck Apr 9, 2020
517d984
Fix bug with proxying previews, add tests
fleck Apr 20, 2020
3d681a9
Fix spacing in engine.
fleck Apr 20, 2020
6d99bd7
Merge branch 'master' of https://github.com/rails/rails into active-s…
fleck May 10, 2020
824c703
Update readme
fleck May 10, 2020
a84d081
Use cache forever method.
fleck May 10, 2020
b787c96
Rename method.
fleck May 10, 2020
aea29e9
Update key methods
fleck May 10, 2020
d375962
extract stream method
fleck May 10, 2020
395e0b3
Document controllers.
fleck May 10, 2020
a7dc7dd
appease rubocop
fleck May 10, 2020
d3a6ba7
Use the block form of http_cache_forever
georgeclaghorn May 11, 2020
178260c
Split tests by controller
georgeclaghorn May 11, 2020
4d14661
Tweak controller names: redirection → redirect
georgeclaghorn May 11, 2020
49027c6
Add CHANGELOG entry
georgeclaghorn May 11, 2020
7558486
Tweak README [ci skip]
georgeclaghorn May 11, 2020
3ee6b44
Update Railties tests for new controller names
georgeclaghorn May 11, 2020
ed22fd4
Update configuring guide [ci skip]
georgeclaghorn May 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions actiontext/test/template/form_helper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def form_with(*, **)
assert_dom_equal \
'<form action="/messages" accept-charset="UTF-8" data-remote="true" method="post">' \
'<input type="hidden" name="message[content]" id="message_content_trix_input_message" />' \
'<trix-editor id="message_content" input="message_content_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/:signed_id/:filename">' \
'<trix-editor id="message_content" input="message_content_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename">' \
"</trix-editor>" \
"</form>",
output_buffer
Expand All @@ -47,7 +47,7 @@ def form_with(*, **)
assert_dom_equal \
'<form action="/messages" accept-charset="UTF-8" data-remote="true" method="post">' \
'<input type="hidden" name="message[content]" id="message_content_trix_input_message" />' \
'<trix-editor id="message_content" input="message_content_trix_input_message" class="custom-class" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/:signed_id/:filename">' \
'<trix-editor id="message_content" input="message_content_trix_input_message" class="custom-class" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename">' \
"</trix-editor>" \
"</form>",
output_buffer
Expand All @@ -61,7 +61,7 @@ def form_with(*, **)
assert_dom_equal \
'<form action="/messages" accept-charset="UTF-8" data-remote="true" method="post">' \
'<input type="hidden" name="message[not_an_attribute]" id="message_not_an_attribute_trix_input_message" />' \
'<trix-editor id="message_not_an_attribute" input="message_not_an_attribute_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/:signed_id/:filename">' \
'<trix-editor id="message_not_an_attribute" input="message_not_an_attribute_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename">' \
"</trix-editor>" \
"</form>",
output_buffer
Expand All @@ -75,7 +75,7 @@ def form_with(*, **)
assert_dom_equal \
'<form action="/messages" accept-charset="UTF-8" data-remote="true" method="post">' \
'<input type="hidden" name="message[content]" id="trix_input_1" />' \
'<trix-editor id="message_content" input="trix_input_1" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/:signed_id/:filename">' \
'<trix-editor id="message_content" input="trix_input_1" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename">' \
"</trix-editor>" \
"</form>",
output_buffer
Expand All @@ -89,7 +89,7 @@ def form_with(*, **)
assert_dom_equal \
'<form action="/messages" accept-charset="UTF-8" data-remote="true" method="post">' \
'<input type="hidden" name="message[content]" id="message_content_trix_input_message" />' \
'<trix-editor placeholder="Content" id="message_content" input="message_content_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/:signed_id/:filename">' \
'<trix-editor placeholder="Content" id="message_content" input="message_content_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename">' \
"</trix-editor>" \
"</form>",
output_buffer
Expand All @@ -105,7 +105,7 @@ def form_with(*, **)
assert_dom_equal \
'<form action="/messages" accept-charset="UTF-8" data-remote="true" method="post">' \
'<input type="hidden" name="message[title]" id="message_title_trix_input_message" />' \
'<trix-editor placeholder="Story title" id="message_title" input="message_title_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/:signed_id/:filename">' \
'<trix-editor placeholder="Story title" id="message_title" input="message_title_trix_input_message" class="trix-content" data-direct-upload-url="http://test.host/rails/active_storage/direct_uploads" data-blob-url-template="http://test.host/rails/active_storage/blobs/redirect/:signed_id/:filename">' \
"</trix-editor>" \
"</form>",
output_buffer
Expand Down
28 changes: 28 additions & 0 deletions activestorage/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
* Files can now be served by proxying them from the underlying storage service
instead of redirecting to a signed service URL. Use the
`rails_storage_proxy_path` and `_url` helpers to proxy an attached file:

```erb
<%= image_tag rails_storage_proxy_path(@user.avatar) %>
```

To proxy by default, set `config.active_storage.resolve_model_to_route`:

```ruby
# Proxy attached files instead.
config.active_storage.resolve_model_to_route = :rails_storage_proxy
```

```erb
<%= image_tag @user.avatar %>
```

To redirect to a signed service URL when the default file serving strategy
is set to proxying, use the `rails_storage_redirect_path` and `_url` helpers:

```erb
<%= image_tag rails_storage_redirect_path(@user.avatar) %>
```

*Jonathan Fleckenstein*

* Add `config.active_storage.web_image_content_types` to allow applications
to add content types (like `image/webp`) in which variants can be processed,
instead of letting those images be converted to the fallback PNG format.
Expand Down
31 changes: 31 additions & 0 deletions activestorage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,37 @@ Variation of image attachment:
<%= image_tag user.avatar.variant(resize_to_limit: [100, 100]) %>
```

## File serving strategies
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Active Storage supports two ways to serve files: redirecting and proxying.

### Redirecting

Active Storage generates stable application URLs for files which, when accessed, redirect to signed, short-lived service URLs. This relieves application servers of the burden of serving file data. It is the default file serving strategy.

When the application is configured to proxy files by default, use the `rails_storage_redirect_path` and `_url` route helpers to redirect instead:

```erb
<%= image_tag rails_storage_redirect_path(@user.avatar) %>
```

### Proxying

Optionally, files can be proxied instead. This means that your application servers will download file data from the storage service in response to requests. This can be useful for serving files from a CDN.

Explicitly proxy attachments using the `rails_storage_proxy_path` and `_url` route helpers:

```erb
<%= image_tag rails_storage_proxy_path(@user.avatar) %>
```

Or configure Active Storage to use proxying by default:

```ruby
# config/initializers/active_storage.rb
Rails.application.config.active_storage.resolve_model_to_route = :rails_storage_proxy
```

## Direct uploads

Active Storage, with its included JavaScript library, supports uploading directly from the client to the cloud.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,13 @@ class ActiveStorage::BaseController < ActionController::Base
include ActiveStorage::SetCurrent

protect_from_forgery with: :exception

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
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# 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
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Note: These URLs are publicly accessible. If you need to enforce access protection beyond the
# security-through-obscurity factor of the signed blob references, you'll need to implement your own
# authenticated redirection controller.
class ActiveStorage::BlobsController < ActiveStorage::BaseController
class ActiveStorage::Blobs::RedirectController < ActiveStorage::BaseController
include ActiveStorage::SetBlob

def show
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

# Proxy files through application. This avoids having a redirect and makes files easier to cache.
class ActiveStorage::Representations::ProxyController < ActiveStorage::BaseController
fleck marked this conversation as resolved.
Show resolved Hide resolved
include ActiveStorage::SetBlob
include ActiveStorage::SetHeaders

def show
http_cache_forever public: true do
set_content_headers_from representation.image
stream representation
end
end

private
def representation
@representation ||= @blob.representation(params[:variation_key]).processed
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Note: These URLs are publicly accessible. If you need to enforce access protection beyond the
# security-through-obscurity factor of the signed blob and variation reference, you'll need to implement your own
# authenticated redirection controller.
class ActiveStorage::RepresentationsController < ActiveStorage::BaseController
class ActiveStorage::Representations::RedirectController < ActiveStorage::BaseController
include ActiveStorage::SetBlob

def show
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 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
response.headers["Content-Disposition"] = ActionDispatch::Http::ContentDisposition.format \
disposition: params[:disposition] || "inline", filename: blob.filename.sanitized
end
fleck marked this conversation as resolved.
Show resolved Hide resolved
end
17 changes: 17 additions & 0 deletions activestorage/app/models/active_storage/preview.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ def url(**options)
alias_method :service_url, :url
deprecate service_url: :url

# Returns a combination key of the blob and the variation that together identifies a specific variant.
def key
if processed?
variant.key
else
raise UnprocessedError
end
end
fleck marked this conversation as resolved.
Show resolved Hide resolved

def download(&block)
if processed?
variant.download(&block)
else
raise UnprocessedError
end
end

private
def processed?
image.attached?
Expand Down
7 changes: 7 additions & 0 deletions activestorage/app/models/active_storage/variant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
class ActiveStorage::Variant
attr_reader :blob, :variation
delegate :service, to: :blob
delegate :content_type, :filename, to: :specification
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fleck this seems to duplicate the definition at line 128 of this same file as now I see these warnings:

activestorage/app/models/active_storage/variant.rb:128: warning: method redefined; discarding old filename
activestorage/app/models/active_storage/variant.rb:59: warning: previous definition of filename was here
activestorage/app/models/active_storage/variant.rb:128: warning: method redefined; discarding old content_type
activestorage/app/models/active_storage/variant.rb:59: warning: previous definition of content_type was here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s me. I missed the definition at line 128. I’ll fix.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 57d926a.


def initialize(blob, variation_or_variation_key)
@blob, @variation = blob, ActiveStorage::Variation.wrap(variation_or_variation_key)
Expand Down Expand Up @@ -83,6 +84,12 @@ def url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline)
alias_method :service_url, :url
deprecate service_url: :url

# Downloads the file associated with this variant. If no block is given, the entire file is read into memory and returned.
# That'll use a lot of RAM for very large files. If a block is given, then the download is streamed and yielded in chunks.
def download(&block)
service.download key, &block
end

# Returns the receiving variant. Allows ActiveStorage::Variant and ActiveStorage::Preview instances to be used interchangeably.
def image
self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ def image
record&.image
end

def url(**options)
image&.url(**options)
end
delegate :key, :url, :download, to: :image, allow_nil: true

alias_method :service_url, :url
deprecate service_url: :url
Expand Down
63 changes: 55 additions & 8 deletions activestorage/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

Rails.application.routes.draw do
scope ActiveStorage.routes_prefix do
get "/blobs/:signed_id/*filename" => "active_storage/blobs#show", as: :rails_service_blob
get "/blobs/redirect/:signed_id/*filename" => "active_storage/blobs/redirect#show", as: :rails_service_blob
get "/blobs/proxy/:signed_id/*filename" => "active_storage/blobs/proxy#show", as: :rails_service_blob_proxy

get "/representations/:signed_blob_id/:variation_key/*filename" => "active_storage/representations#show", as: :rails_blob_representation
get "/representations/redirect/:signed_blob_id/:variation_key/*filename" => "active_storage/representations/redirect#show", as: :rails_blob_representation
get "/representations/proxy/:signed_blob_id/:variation_key/*filename" => "active_storage/representations/proxy#show", as: :rails_blob_representation_proxy

get "/disk/:encoded_key/*filename" => "active_storage/disk#show", as: :rails_disk_service
put "/disk/:encoded_token" => "active_storage/disk#update", as: :update_rails_disk_service
Expand All @@ -19,15 +21,60 @@
route_for(:rails_blob_representation, signed_blob_id, variation_key, filename, options)
end

resolve("ActiveStorage::Variant") { |variant, options| route_for(:rails_representation, variant, options) }
resolve("ActiveStorage::VariantWithRecord") { |variant, options| route_for(:rails_representation, variant, options) }
resolve("ActiveStorage::Preview") { |preview, options| route_for(:rails_representation, preview, options) }

resolve("ActiveStorage::Variant") { |variant, options| route_for(ActiveStorage.resolve_model_to_route, variant, options) }
resolve("ActiveStorage::VariantWithRecord") { |variant, options| route_for(ActiveStorage.resolve_model_to_route, variant, options) }
resolve("ActiveStorage::Preview") { |preview, options| route_for(ActiveStorage.resolve_model_to_route, preview, options) }

direct :rails_blob do |blob, options|
route_for(:rails_service_blob, blob.signed_id, blob.filename, options)
end

resolve("ActiveStorage::Blob") { |blob, options| route_for(:rails_blob, blob, options) }
resolve("ActiveStorage::Attachment") { |attachment, options| route_for(:rails_blob, attachment.blob, options) }
resolve("ActiveStorage::Blob") { |blob, options| route_for(ActiveStorage.resolve_model_to_route, blob, options) }
resolve("ActiveStorage::Attachment") { |attachment, options| route_for(ActiveStorage.resolve_model_to_route, attachment.blob, options) }

direct :rails_storage_proxy do |model, options|
if model.respond_to?(:signed_id)
route_for(
:rails_service_blob_proxy,
model.signed_id,
model.filename,
options
)
else
signed_blob_id = model.blob.signed_id
variation_key = model.variation.key
filename = model.blob.filename

route_for(
:rails_blob_representation_proxy,
signed_blob_id,
variation_key,
filename,
options
)
end
end

direct :rails_storage_redirect do |model, options|
if model.respond_to?(:signed_id)
route_for(
:rails_service_blob,
model.signed_id,
model.filename,
options
)
else
signed_blob_id = model.blob.signed_id
variation_key = model.variation.key
filename = model.blob.filename

route_for(
:rails_blob_representation,
signed_blob_id,
variation_key,
filename,
options
)
end
end
end if ActiveStorage.draw_routes
1 change: 1 addition & 0 deletions activestorage/lib/active_storage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ module ActiveStorage

mattr_accessor :routes_prefix, default: "/rails/active_storage"
mattr_accessor :draw_routes, default: true
mattr_accessor :resolve_model_to_route, default: :rails_storage_redirect

mattr_accessor :replace_on_assign_to_many, default: false
mattr_accessor :track_variants, default: false
Expand Down
1 change: 1 addition & 0 deletions activestorage/lib/active_storage/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class Engine < Rails::Engine # :nodoc:
ActiveStorage.paths = app.config.active_storage.paths || {}
ActiveStorage.routes_prefix = app.config.active_storage.routes_prefix || "/rails/active_storage"
ActiveStorage.draw_routes = app.config.active_storage.draw_routes != false
ActiveStorage.resolve_model_to_route = app.config.active_storage.resolve_model_to_route || :rails_storage_redirect

ActiveStorage.variable_content_types = app.config.active_storage.variable_content_types || []
ActiveStorage.web_image_content_types = app.config.active_storage.web_image_content_types || []
Expand Down
21 changes: 21 additions & 0 deletions activestorage/test/controllers/blobs/proxy_controller_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

require "test_helper"
require "database/setup"

class ActiveStorage::Blobs::ProxyControllerTest < ActionDispatch::IntegrationTest
setup do
@blob = create_file_blob filename: "racecar.jpg"
end

test "invalid signed ID" do
get rails_service_blob_proxy_url("invalid", "racecar.jpg")
assert_response :not_found
end

test "HTTP caching" do
get rails_storage_proxy_url(@blob)
assert_response :success
assert_equal "max-age=3155695200, public", response.headers["Cache-Control"]
end
end