aboutsummaryrefslogtreecommitdiffstats
path: root/activestorage
diff options
context:
space:
mode:
Diffstat (limited to 'activestorage')
-rw-r--r--activestorage/CHANGELOG.md86
-rw-r--r--activestorage/config/routes.rb2
-rw-r--r--activestorage/lib/active_storage.rb19
-rw-r--r--activestorage/lib/active_storage/analyzer/image_analyzer.rb3
-rw-r--r--activestorage/lib/active_storage/attached/model.rb17
-rw-r--r--activestorage/lib/active_storage/engine.rb3
-rw-r--r--activestorage/lib/active_storage/service/disk_service.rb6
-rw-r--r--activestorage/test/analyzer/video_analyzer_test.rb1
-rw-r--r--activestorage/test/models/attached/many_test.rb26
-rw-r--r--activestorage/test/service/disk_service_test.rb10
10 files changed, 122 insertions, 51 deletions
diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md
index 351d8687a4..1475a7a786 100644
--- a/activestorage/CHANGELOG.md
+++ b/activestorage/CHANGELOG.md
@@ -1,50 +1,64 @@
-* Method calls on singular attachments return `nil` when no file is attached.
+* Add `config.active_storage.draw_routes` to disable Active Storage routes.
- Previously, assuming the following User model, `user.avatar.filename` would
- raise a `Module::DelegationError` if no avatar was attached:
+ *Gannon McGibbon*
- ```ruby
- class User < ApplicationRecord
- has_one_attached :avatar
- end
- ```
-
- They now return `nil`.
+* Image analysis is skipped if ImageMagick returns an error.
- *Matthew Tanous*
+ `ActiveStorage::Analyzer::ImageAnalyzer#metadata` would previously raise a
+ `MiniMagick::Error`, which caused persistent `ActiveStorage::AnalyzeJob`
+ failures. It now logs the error and returns `{}`, resulting in no metadata
+ being added to the offending image blob.
-* The mirror service supports direct uploads.
+ *George Claghorn*
- New files are directly uploaded to the primary service. When a
- directly-uploaded file is attached to a record, a background job is enqueued
- to copy it to each secondary service.
+* Method calls on singular attachments return `nil` when no file is attached.
- Configure the queue used to process mirroring jobs by setting
- `config.active_storage.queues.mirror`. The default is `:active_storage_mirror`.
+ Previously, assuming the following User model, `user.avatar.filename` would
+ raise a `Module::DelegationError` if no avatar was attached:
- *George Claghorn*
+ ```ruby
+ class User < ApplicationRecord
+ has_one_attached :avatar
+ end
+ ```
-* The S3 service now permits uploading files larger than 5 gigabytes.
+ They now return `nil`.
- When uploading a file greater than 100 megabytes in size, the service
- transparently switches to [multipart uploads](https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html)
- using a part size computed from the file's total size and S3's part count limit.
+ *Matthew Tanous*
- No application changes are necessary to take advantage of this feature. You
- can customize the default 100 MB multipart upload threshold in your S3
- service's configuration:
+* The mirror service supports direct uploads.
- ```yaml
- production:
- service: s3
- access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
- secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
- region: us-east-1
- bucket: my-bucket
- upload:
- multipart_threshold: <%= 250.megabytes %>
- ```
+ New files are directly uploaded to the primary service. When a
+ directly-uploaded file is attached to a record, a background job is enqueued
+ to copy it to each secondary service.
+
+ Configure the queue used to process mirroring jobs by setting
+ `config.active_storage.queues.mirror`. The default is `:active_storage_mirror`.
+
+ *George Claghorn*
+
+* The S3 service now permits uploading files larger than 5 gigabytes.
+
+ When uploading a file greater than 100 megabytes in size, the service
+ transparently switches to [multipart uploads](https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html)
+ using a part size computed from the file's total size and S3's part count limit.
+
+ No application changes are necessary to take advantage of this feature. You
+ can customize the default 100 MB multipart upload threshold in your S3
+ service's configuration:
+
+ ```yaml
+ production:
+ service: s3
+ access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
+ secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
+ region: us-east-1
+ bucket: my-bucket
+ upload:
+ multipart_threshold: <%= 250.megabytes %>
+ ```
+
+ *George Claghorn*
- *George Claghorn*
Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/activestorage/CHANGELOG.md) for previous changes.
diff --git a/activestorage/config/routes.rb b/activestorage/config/routes.rb
index 3af7361cff..bde53e72f3 100644
--- a/activestorage/config/routes.rb
+++ b/activestorage/config/routes.rb
@@ -29,4 +29,4 @@ Rails.application.routes.draw do
resolve("ActiveStorage::Blob") { |blob, options| route_for(:rails_blob, blob, options) }
resolve("ActiveStorage::Attachment") { |attachment, options| route_for(:rails_blob, attachment.blob, options) }
-end
+end if ActiveStorage.draw_routes
diff --git a/activestorage/lib/active_storage.rb b/activestorage/lib/active_storage.rb
index 5c5da551ae..c35a9920d6 100644
--- a/activestorage/lib/active_storage.rb
+++ b/activestorage/lib/active_storage.rb
@@ -43,17 +43,26 @@ module ActiveStorage
mattr_accessor :logger
mattr_accessor :verifier
+ mattr_accessor :variant_processor, default: :mini_magick
+
mattr_accessor :queues, default: {}
+
mattr_accessor :previewers, default: []
- mattr_accessor :analyzers, default: []
- mattr_accessor :variant_processor, default: :mini_magick
+ mattr_accessor :analyzers, default: []
+
mattr_accessor :paths, default: {}
- mattr_accessor :variable_content_types, default: []
+
+ mattr_accessor :variable_content_types, default: []
+ mattr_accessor :binary_content_type, default: "application/octet-stream"
mattr_accessor :content_types_to_serve_as_binary, default: []
- mattr_accessor :content_types_allowed_inline, default: []
- mattr_accessor :binary_content_type, default: "application/octet-stream"
+ mattr_accessor :content_types_allowed_inline, default: []
+
mattr_accessor :service_urls_expire_in, default: 5.minutes
+
mattr_accessor :routes_prefix, default: "/rails/active_storage"
+ mattr_accessor :draw_routes, default: true
+
+ mattr_accessor :replace_on_assign_to_many, default: false
module Transformers
extend ActiveSupport::Autoload
diff --git a/activestorage/lib/active_storage/analyzer/image_analyzer.rb b/activestorage/lib/active_storage/analyzer/image_analyzer.rb
index c8bc8fe953..bd1bef3076 100644
--- a/activestorage/lib/active_storage/analyzer/image_analyzer.rb
+++ b/activestorage/lib/active_storage/analyzer/image_analyzer.rb
@@ -43,6 +43,9 @@ module ActiveStorage
rescue LoadError
logger.info "Skipping image analysis because the mini_magick gem isn't installed"
{}
+ rescue MiniMagick::Error => error
+ logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
+ {}
end
def rotated_image?(image)
diff --git a/activestorage/lib/active_storage/attached/model.rb b/activestorage/lib/active_storage/attached/model.rb
index ae7f0685f2..06864a846f 100644
--- a/activestorage/lib/active_storage/attached/model.rb
+++ b/activestorage/lib/active_storage/attached/model.rb
@@ -93,12 +93,19 @@ module ActiveStorage
end
def #{name}=(attachables)
- attachment_changes["#{name}"] =
- if attachables.nil? || Array(attachables).none?
- ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
- else
- ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
+ if ActiveStorage.replace_on_assign_to_many
+ attachment_changes["#{name}"] =
+ if attachables.nil? || Array(attachables).none?
+ ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
+ else
+ ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
+ end
+ else
+ if !attachables.nil? || Array(attachables).any?
+ attachment_changes["#{name}"] =
+ ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
end
+ end
end
CODE
diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb
index f70d0a512a..9d9cd02d12 100644
--- a/activestorage/lib/active_storage/engine.rb
+++ b/activestorage/lib/active_storage/engine.rb
@@ -73,12 +73,15 @@ module ActiveStorage
ActiveStorage.analyzers = app.config.active_storage.analyzers || []
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.variable_content_types = app.config.active_storage.variable_content_types || []
ActiveStorage.content_types_to_serve_as_binary = app.config.active_storage.content_types_to_serve_as_binary || []
ActiveStorage.service_urls_expire_in = app.config.active_storage.service_urls_expire_in || 5.minutes
ActiveStorage.content_types_allowed_inline = app.config.active_storage.content_types_allowed_inline || []
ActiveStorage.binary_content_type = app.config.active_storage.binary_content_type || "application/octet-stream"
+
+ ActiveStorage.replace_on_assign_to_many = app.config.active_storage.replace_on_assign_to_many || false
end
end
diff --git a/activestorage/lib/active_storage/service/disk_service.rb b/activestorage/lib/active_storage/service/disk_service.rb
index 67892d43b2..764a447c69 100644
--- a/activestorage/lib/active_storage/service/disk_service.rb
+++ b/activestorage/lib/active_storage/service/disk_service.rb
@@ -84,8 +84,12 @@ module ActiveStorage
purpose: :blob_key }
)
+ current_uri = URI.parse(current_host)
+
generated_url = url_helpers.rails_disk_service_url(verified_key_with_expiration,
- host: current_host,
+ protocol: current_uri.scheme,
+ host: current_uri.host,
+ port: current_uri.port,
disposition: content_disposition,
content_type: content_type,
filename: filename
diff --git a/activestorage/test/analyzer/video_analyzer_test.rb b/activestorage/test/analyzer/video_analyzer_test.rb
index d30f49315a..172a2f0aae 100644
--- a/activestorage/test/analyzer/video_analyzer_test.rb
+++ b/activestorage/test/analyzer/video_analyzer_test.rb
@@ -24,7 +24,6 @@ class ActiveStorage::Analyzer::VideoAnalyzerTest < ActiveSupport::TestCase
assert_equal 480, metadata[:width]
assert_equal 640, metadata[:height]
assert_equal [4, 3], metadata[:display_aspect_ratio]
- assert_equal 5.227975, metadata[:duration]
assert_equal 90, metadata[:angle]
end
diff --git a/activestorage/test/models/attached/many_test.rb b/activestorage/test/models/attached/many_test.rb
index 878e284049..39ddecb041 100644
--- a/activestorage/test/models/attached/many_test.rb
+++ b/activestorage/test/models/attached/many_test.rb
@@ -269,6 +269,24 @@ class ActiveStorage::ManyAttachedTest < ActiveSupport::TestCase
end
end
+ test "updating an existing record with attachments when appending on assign" do
+ append_on_assign do
+ @user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg")
+
+ assert_difference -> { @user.reload.highlights.count }, +2 do
+ @user.update! highlights: [ create_blob(filename: "whenever.jpg"), create_blob(filename: "wherever.jpg") ]
+ end
+
+ assert_no_difference -> { @user.reload.highlights.count } do
+ @user.update! highlights: [ ]
+ end
+
+ assert_no_difference -> { @user.reload.highlights.count } do
+ @user.update! highlights: nil
+ end
+ end
+ end
+
test "attaching existing blobs to a new record" do
User.new(name: "Jason").tap do |user|
user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "town.jpg")
@@ -538,4 +556,12 @@ class ActiveStorage::ManyAttachedTest < ActiveSupport::TestCase
User.remove_method :highlights
end
end
+
+ private
+ def append_on_assign
+ ActiveStorage.replace_on_assign_to_many, previous = false, ActiveStorage.replace_on_assign_to_many
+ yield
+ ensure
+ ActiveStorage.replace_on_assign_to_many = previous
+ end
end
diff --git a/activestorage/test/service/disk_service_test.rb b/activestorage/test/service/disk_service_test.rb
index f3c4dd26bd..b766cc3f56 100644
--- a/activestorage/test/service/disk_service_test.rb
+++ b/activestorage/test/service/disk_service_test.rb
@@ -8,8 +8,14 @@ class ActiveStorage::Service::DiskServiceTest < ActiveSupport::TestCase
include ActiveStorage::Service::SharedServiceTests
test "URL generation" do
- assert_match(/^https:\/\/example.com\/rails\/active_storage\/disk\/.*\/avatar\.png\?content_type=image%2Fpng&disposition=inline/,
- @service.url(@key, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png"))
+ original_url_options = Rails.application.routes.default_url_options.dup
+ Rails.application.routes.default_url_options.merge!(protocol: "http", host: "test.example.com", port: 3001)
+ begin
+ assert_match(/^https:\/\/example.com\/rails\/active_storage\/disk\/.*\/avatar\.png\?content_type=image%2Fpng&disposition=inline/,
+ @service.url(@key, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png"))
+ ensure
+ Rails.application.routes.default_url_options = original_url_options
+ end
end
test "headers_for_direct_upload generation" do