Skip to content

Commit f8f18a9

Browse files
authored
Merge pull request rails#42535 from crawler/active-storage-strict-loading-support
Active storage representations controllers strict_loading_by_default support
2 parents 36aee3f + 14ea877 commit f8f18a9

File tree

8 files changed

+162
-2
lines changed

8 files changed

+162
-2
lines changed

activestorage/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
* Add support of `strict_loading_by_default` to `ActiveStorage::Representations` controllers
2+
3+
*Anton Topchii*, *Andrew White*
4+
15
* Allow to detach an attachment when record is not persisted
26

37
*Jacopo Beschi*
48

5-
* Use libvips instead of ImageMagick to analyze images when `active_storage.variant_processor = vips`
9+
* Use libvips instead of ImageMagick to analyze images when `active_storage.variant_processor = vips`
610

711
*Breno Gazzola*
812

activestorage/app/controllers/active_storage/representations/base_controller.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ class ActiveStorage::Representations::BaseController < ActiveStorage::BaseContro
66
before_action :set_representation
77

88
private
9+
def blob_scope
10+
ActiveStorage::Blob.scope_for_strict_loading
11+
end
12+
913
def set_representation
1014
@representation = @blob.representation(params[:variation_key]).processed
1115
rescue ActiveSupport::MessageVerifier::InvalidSignature

activestorage/app/controllers/concerns/active_storage/set_blob.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ module ActiveStorage::SetBlob #:nodoc:
99

1010
private
1111
def set_blob
12-
@blob = ActiveStorage::Blob.find_signed!(params[:signed_blob_id] || params[:signed_id])
12+
@blob = blob_scope.find_signed!(params[:signed_blob_id] || params[:signed_id])
1313
rescue ActiveSupport::MessageVerifier::InvalidSignature
1414
head :not_found
1515
end
16+
17+
def blob_scope
18+
ActiveStorage::Blob
19+
end
1620
end

activestorage/app/models/active_storage/blob.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ def combine_signed_id_purposes(purpose) #:nodoc:
148148
def signed_id_verifier #:nodoc:
149149
@signed_id_verifier ||= ActiveStorage.verifier
150150
end
151+
152+
def scope_for_strict_loading #:nodoc:
153+
if strict_loading_by_default? && ActiveStorage.track_variants
154+
includes(variant_records: { image_attachment: :blob }, preview_image_attachment: :blob)
155+
else
156+
all
157+
end
158+
end
151159
end
152160

153161
# Returns a signed ID for this blob that's suitable for reference on the client-side without fear of tampering.

activestorage/test/controllers/representations/proxy_controller_test.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,29 @@ class ActiveStorage::Representations::ProxyControllerWithVariantsTest < ActionDi
4141
end
4242
end
4343

44+
class ActiveStorage::Representations::ProxyControllerWithVariantsWithStrictLoadingTest < ActionDispatch::IntegrationTest
45+
setup do
46+
@blob = create_file_blob filename: "racecar.jpg"
47+
@blob.variant(resize: "100x100").processed
48+
end
49+
50+
test "showing existing variant record" do
51+
with_strict_loading_by_default do
52+
get rails_blob_representation_proxy_url(
53+
filename: @blob.filename,
54+
signed_blob_id: @blob.signed_id,
55+
variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
56+
end
57+
assert_response :ok
58+
assert_match(/^inline/, response.headers["Content-Disposition"])
59+
60+
@blob.reload # became free of strict_loading?
61+
image = read_image(@blob.variant(resize: "100x100"))
62+
assert_equal 100, image.width
63+
assert_equal 67, image.height
64+
end
65+
end
66+
4467
class ActiveStorage::Representations::ProxyControllerWithPreviewsTest < ActionDispatch::IntegrationTest
4568
setup do
4669
@blob = create_file_blob filename: "report.pdf", content_type: "application/pdf"
@@ -80,3 +103,28 @@ class ActiveStorage::Representations::ProxyControllerWithPreviewsTest < ActionDi
80103
assert_response :not_found
81104
end
82105
end
106+
107+
class ActiveStorage::Representations::ProxyControllerWithPreviewsWithStrictLoadingTest < ActionDispatch::IntegrationTest
108+
setup do
109+
@blob = create_file_blob filename: "report.pdf", content_type: "application/pdf"
110+
@blob.preview(resize: "100x100").processed
111+
end
112+
113+
test "showing existing preview record" do
114+
with_strict_loading_by_default do
115+
get rails_blob_representation_proxy_url(
116+
filename: @blob.filename,
117+
signed_blob_id: @blob.signed_id,
118+
variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
119+
end
120+
121+
assert_response :ok
122+
assert_match(/^inline/, response.headers["Content-Disposition"])
123+
@blob.reload # became free of strict_loading?
124+
assert_predicate @blob.preview_image, :attached?
125+
126+
image = read_image(@blob.preview_image.variant(resize: "100x100").processed)
127+
assert_equal 77, image.width
128+
assert_equal 100, image.height
129+
end
130+
end

activestorage/test/controllers/representations/redirect_controller_test.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,31 @@ class ActiveStorage::Representations::RedirectControllerWithVariantsTest < Actio
4242
end
4343
end
4444

45+
class ActiveStorage::Representations::RedirectControllerWithVariantsWithStrictLoadingTest < ActionDispatch::IntegrationTest
46+
setup do
47+
@blob = create_file_blob filename: "racecar.jpg"
48+
@blob.variant(resize: "100x100").processed
49+
end
50+
51+
test "showing existing variant record inline" do
52+
with_strict_loading_by_default do
53+
get rails_blob_representation_url(
54+
filename: @blob.filename,
55+
signed_blob_id: @blob.signed_id,
56+
variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
57+
end
58+
59+
assert_redirected_to(/racecar\.jpg/)
60+
follow_redirect!
61+
assert_match(/^inline/, response.headers["Content-Disposition"])
62+
63+
@blob.reload # became free of strict_loading?
64+
image = read_image(@blob.variant(resize: "100x100"))
65+
assert_equal 100, image.width
66+
assert_equal 67, image.height
67+
end
68+
end
69+
4570
class ActiveStorage::Representations::RedirectControllerWithPreviewsTest < ActionDispatch::IntegrationTest
4671
setup do
4772
@blob = create_file_blob filename: "report.pdf", content_type: "application/pdf"
@@ -81,3 +106,29 @@ class ActiveStorage::Representations::RedirectControllerWithPreviewsTest < Actio
81106
assert_response :not_found
82107
end
83108
end
109+
110+
class ActiveStorage::Representations::RedirectControllerWithPreviewsWithStrictLoadingTest < ActionDispatch::IntegrationTest
111+
setup do
112+
@blob = create_file_blob filename: "report.pdf", content_type: "application/pdf"
113+
@blob.preview(resize: "100x100").processed
114+
end
115+
116+
test "showing existing preview record inline" do
117+
with_strict_loading_by_default do
118+
get rails_blob_representation_url(
119+
filename: @blob.filename,
120+
signed_blob_id: @blob.signed_id,
121+
variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
122+
end
123+
124+
assert_predicate @blob.preview_image, :attached?
125+
assert_redirected_to(/report\.png/)
126+
follow_redirect!
127+
assert_match(/^inline/, response.headers["Content-Disposition"])
128+
129+
@blob.reload # became free of strict_loading?
130+
image = read_image(@blob.preview_image.variant(resize: "100x100"))
131+
assert_equal 77, image.width
132+
assert_equal 100, image.height
133+
end
134+
end

activestorage/test/models/blob_test.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,33 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase
286286
end
287287
end
288288

289+
test "scope_for_strict_loading adds includes only when track_variants and strict_loading_by_default" do
290+
assert_empty(
291+
ActiveStorage::Blob.scope_for_strict_loading.includes_values,
292+
"Expected ActiveStorage::Blob.scope_for_strict_loading have no includes"
293+
)
294+
295+
with_strict_loading_by_default do
296+
includes_values = ActiveStorage::Blob.scope_for_strict_loading.includes_values
297+
298+
assert(
299+
includes_values.any? { |values| values[:variant_records] == { image_attachment: :blob } },
300+
"Expected ActiveStorage::Blob.scope_for_strict_loading to have variant_records included"
301+
)
302+
assert(
303+
includes_values.any? { |values| values[:preview_image_attachment] == :blob },
304+
"Expected ActiveStorage::Blob.scope_for_strict_loading to have preview_image_attachment included"
305+
)
306+
307+
without_variant_tracking do
308+
assert_empty(
309+
ActiveStorage::Blob.scope_for_strict_loading.includes_values,
310+
"Expected ActiveStorage::Blob.scope_for_strict_loading have no includes"
311+
)
312+
end
313+
end
314+
end
315+
289316
private
290317
def expected_url_for(blob, disposition: :attachment, filename: nil, content_type: nil, service_name: :local)
291318
filename ||= blob.filename

activestorage/test/test_helper.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,20 @@ def with_service(service_name)
125125
ensure
126126
ActiveStorage::Blob.service = previous_service
127127
end
128+
129+
def with_strict_loading_by_default(&block)
130+
strict_loading_was = ActiveRecord::Base.strict_loading_by_default
131+
ActiveRecord::Base.strict_loading_by_default = true
132+
yield
133+
ActiveRecord::Base.strict_loading_by_default = strict_loading_was
134+
end
135+
136+
def without_variant_tracking(&block)
137+
variant_tracking_was = ActiveStorage.track_variants
138+
ActiveStorage.track_variants = false
139+
yield
140+
ActiveStorage.track_variants = variant_tracking_was
141+
end
128142
end
129143

130144
require "global_id"

0 commit comments

Comments
 (0)