aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activestorage/CHANGELOG.md15
-rw-r--r--activestorage/app/models/active_storage/blob.rb17
-rw-r--r--activestorage/test/models/blob_test.rb10
-rw-r--r--activestorage/test/test_helper.rb4
-rw-r--r--guides/source/active_storage_overview.md12
5 files changed, 49 insertions, 9 deletions
diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md
index 4c12adae56..679ca0df03 100644
--- a/activestorage/CHANGELOG.md
+++ b/activestorage/CHANGELOG.md
@@ -1,3 +1,18 @@
+* Pass in `identify: false` as an argument when providing a `content_type` for
+ `ActiveStorage::Attached::{One,Many}#attach` to bypass automatic content
+ type inference. For example:
+
+ ```ruby
+ @message.image.attach(
+ io: File.open('/path/to/file'),
+ filename: 'file.pdf',
+ content_type: 'application/pdf',
+ identify: false
+ )
+ ```
+
+ *Ryan Davidson*
+
* The Google Cloud Storage service properly supports streaming downloads.
It now requires version 1.11 or newer of the google-cloud-storage gem.
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb
index 0cd4ad8128..b8b3b62f22 100644
--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -44,21 +44,23 @@ class ActiveStorage::Blob < ActiveRecord::Base
end
# Returns a new, unsaved blob instance after the +io+ has been uploaded to the service.
- def build_after_upload(io:, filename:, content_type: nil, metadata: nil)
+ # When providing a content type, pass <tt>identify: false</tt> to bypass automatic content type inference.
+ def build_after_upload(io:, filename:, content_type: nil, metadata: nil, identify: true)
new.tap do |blob|
blob.filename = filename
blob.content_type = content_type
blob.metadata = metadata
- blob.upload io
+ blob.upload(io, identify: identify)
end
end
# Returns a saved blob instance after the +io+ has been uploaded to the service. Note, the blob is first built,
# then the +io+ is uploaded, then the blob is saved. This is done this way to avoid uploading (which may take
# time), while having an open database transaction.
- def create_after_upload!(io:, filename:, content_type: nil, metadata: nil)
- build_after_upload(io: io, filename: filename, content_type: content_type, metadata: metadata).tap(&:save!)
+ # When providing a content type, pass <tt>identify: false</tt> to bypass automatic content type inference.
+ def create_after_upload!(io:, filename:, content_type: nil, metadata: nil, identify: true)
+ build_after_upload(io: io, filename: filename, content_type: content_type, metadata: metadata, identify: identify).tap(&:save!)
end
# Returns a saved blob _without_ uploading a file to the service. This blob will point to a key where there is
@@ -142,13 +144,14 @@ class ActiveStorage::Blob < ActiveRecord::Base
#
# Prior to uploading, we compute the checksum, which is sent to the service for transit integrity validation. If the
# checksum does not match what the service receives, an exception will be raised. We also measure the size of the +io+
- # and store that in +byte_size+ on the blob record.
+ # and store that in +byte_size+ on the blob record. The content type is automatically extracted from the +io+ unless
+ # you specify a +content_type+ and pass +identify+ as false.
#
# Normally, you do not have to call this method directly at all. Use the factory class methods of +build_after_upload+
# and +create_after_upload!+.
- def upload(io)
+ def upload(io, identify: true)
self.checksum = compute_checksum_in_chunks(io)
- self.content_type = extract_content_type(io)
+ self.content_type = extract_content_type(io) if content_type.nil? || identify
self.byte_size = io.size
self.identified = true
diff --git a/activestorage/test/models/blob_test.rb b/activestorage/test/models/blob_test.rb
index daa01015f7..17151117db 100644
--- a/activestorage/test/models/blob_test.rb
+++ b/activestorage/test/models/blob_test.rb
@@ -43,6 +43,16 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase
assert_equal "text/plain", blob.content_type
end
+ test "create after upload extracts content_type from io when no content_type given and identify: false" do
+ blob = create_blob content_type: nil, identify: false
+ assert_equal "text/plain", blob.content_type
+ end
+
+ test "create after upload uses content_type when identify: false" do
+ blob = create_blob data: "Article,dates,analysis\n1, 2, 3", filename: "table.csv", content_type: "text/csv", identify: false
+ assert_equal "text/csv", blob.content_type
+ end
+
test "image?" do
blob = create_file_blob filename: "racecar.jpg"
assert_predicate blob, :image?
diff --git a/activestorage/test/test_helper.rb b/activestorage/test/test_helper.rb
index 499d955a2f..573a8e0b0b 100644
--- a/activestorage/test/test_helper.rb
+++ b/activestorage/test/test_helper.rb
@@ -50,8 +50,8 @@ class ActiveSupport::TestCase
end
private
- def create_blob(data: "Hello world!", filename: "hello.txt", content_type: "text/plain")
- ActiveStorage::Blob.create_after_upload! io: StringIO.new(data), filename: filename, content_type: content_type
+ def create_blob(data: "Hello world!", filename: "hello.txt", content_type: "text/plain", identify: true)
+ ActiveStorage::Blob.create_after_upload! io: StringIO.new(data), filename: filename, content_type: content_type, identify: identify
end
def create_file_blob(filename: "racecar.jpg", content_type: "image/jpeg", metadata: nil)
diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md
index 09af899074..292928488b 100644
--- a/guides/source/active_storage_overview.md
+++ b/guides/source/active_storage_overview.md
@@ -319,6 +319,18 @@ type you provide if it can’t do that.
@message.image.attach(io: File.open('/path/to/file'), filename: 'file.pdf', content_type: 'application/pdf')
```
+You can bypass the content type inference from the data by passing in
+`identify: false` along with the `content_type`.
+
+```ruby
+@message.image.attach(
+ io: File.open('/path/to/file'),
+ filename: 'file.pdf',
+ content_type: 'application/pdf'
+ identify: false
+)
+```
+
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.