aboutsummaryrefslogtreecommitdiffstats
path: root/activestorage
diff options
context:
space:
mode:
Diffstat (limited to 'activestorage')
-rw-r--r--activestorage/README.md8
-rw-r--r--activestorage/Rakefile2
-rw-r--r--activestorage/app/controllers/active_storage/blobs_controller.rb3
-rw-r--r--activestorage/app/controllers/active_storage/direct_uploads_controller.rb2
-rw-r--r--activestorage/app/controllers/active_storage/disk_controller.rb2
-rw-r--r--activestorage/app/controllers/active_storage/variants_controller.rb3
-rw-r--r--activestorage/app/jobs/active_storage/purge_job.rb4
-rw-r--r--activestorage/app/models/active_storage/attachment.rb4
-rw-r--r--activestorage/app/models/active_storage/blob.rb38
-rw-r--r--activestorage/app/models/active_storage/filename.rb2
-rw-r--r--activestorage/app/models/active_storage/variant.rb16
-rw-r--r--activestorage/app/models/active_storage/variation.rb10
-rw-r--r--activestorage/config/routes.rb2
-rw-r--r--activestorage/db/migrate/20170806125915_create_active_storage_tables.rb27
-rw-r--r--activestorage/lib/active_storage.rb2
-rw-r--r--activestorage/lib/active_storage/attached.rb6
-rw-r--r--activestorage/lib/active_storage/attached/macros.rb48
-rw-r--r--activestorage/lib/active_storage/attached/many.rb5
-rw-r--r--activestorage/lib/active_storage/attached/one.rb2
-rw-r--r--activestorage/lib/active_storage/engine.rb29
-rw-r--r--activestorage/lib/active_storage/gem_version.rb2
-rw-r--r--activestorage/lib/active_storage/log_subscriber.rb4
-rw-r--r--activestorage/lib/active_storage/migration.rb27
-rw-r--r--activestorage/lib/active_storage/service.rb26
-rw-r--r--activestorage/lib/active_storage/service/azure_storage_service.rb9
-rw-r--r--activestorage/lib/active_storage/service/configurator.rb2
-rw-r--r--activestorage/lib/active_storage/service/disk_service.rb5
-rw-r--r--activestorage/lib/active_storage/service/gcs_service.rb4
-rw-r--r--activestorage/lib/active_storage/service/mirror_service.rb14
-rw-r--r--activestorage/lib/active_storage/service/s3_service.rb4
-rw-r--r--activestorage/lib/active_storage/version.rb2
-rw-r--r--activestorage/lib/tasks/activestorage.rake11
-rw-r--r--activestorage/test/controllers/blobs_controller_test.rb17
-rw-r--r--activestorage/test/controllers/direct_uploads_controller_test.rb2
-rw-r--r--activestorage/test/controllers/disk_controller_test.rb2
-rw-r--r--activestorage/test/controllers/variants_controller_test.rb2
-rw-r--r--activestorage/test/database/create_users_migration.rb2
-rw-r--r--activestorage/test/database/setup.rb5
-rw-r--r--activestorage/test/dummy/Rakefile2
-rw-r--r--activestorage/test/dummy/app/controllers/application_controller.rb2
-rw-r--r--activestorage/test/dummy/app/helpers/application_helper.rb2
-rw-r--r--activestorage/test/dummy/app/jobs/application_job.rb2
-rw-r--r--activestorage/test/dummy/app/models/application_record.rb2
-rwxr-xr-xactivestorage/test/dummy/bin/bundle2
-rwxr-xr-xactivestorage/test/dummy/bin/rails2
-rwxr-xr-xactivestorage/test/dummy/bin/rake2
-rwxr-xr-xactivestorage/test/dummy/bin/yarn2
-rw-r--r--activestorage/test/dummy/config.ru2
-rw-r--r--activestorage/test/dummy/config/application.rb2
-rw-r--r--activestorage/test/dummy/config/boot.rb2
-rw-r--r--activestorage/test/dummy/config/environment.rb2
-rw-r--r--activestorage/test/dummy/config/environments/development.rb2
-rw-r--r--activestorage/test/dummy/config/environments/production.rb2
-rw-r--r--activestorage/test/dummy/config/environments/test.rb2
-rw-r--r--activestorage/test/dummy/config/initializers/application_controller_renderer.rb1
-rw-r--r--activestorage/test/dummy/config/initializers/assets.rb2
-rw-r--r--activestorage/test/dummy/config/initializers/backtrace_silencers.rb1
-rw-r--r--activestorage/test/dummy/config/initializers/cookies_serializer.rb2
-rw-r--r--activestorage/test/dummy/config/initializers/filter_parameter_logging.rb2
-rw-r--r--activestorage/test/dummy/config/initializers/inflections.rb1
-rw-r--r--activestorage/test/dummy/config/initializers/mime_types.rb1
-rw-r--r--activestorage/test/dummy/config/initializers/wrap_parameters.rb2
-rw-r--r--activestorage/test/dummy/config/routes.rb2
-rw-r--r--activestorage/test/dummy/config/spring.rb2
-rw-r--r--activestorage/test/filename_test.rb6
-rw-r--r--activestorage/test/models/attachments_test.rb17
-rw-r--r--activestorage/test/models/blob_test.rb2
-rw-r--r--activestorage/test/models/variant_test.rb2
-rw-r--r--activestorage/test/service/azure_storage_service_test.rb11
-rw-r--r--activestorage/test/service/configurations.yml14
-rw-r--r--activestorage/test/service/configurator_test.rb2
-rw-r--r--activestorage/test/service/disk_service_test.rb2
-rw-r--r--activestorage/test/service/gcs_service_test.rb2
-rw-r--r--activestorage/test/service/mirror_service_test.rb2
-rw-r--r--activestorage/test/service/s3_service_test.rb2
-rw-r--r--activestorage/test/service/shared_service_tests.rb4
-rw-r--r--activestorage/test/template/image_tag_test.rb6
-rw-r--r--activestorage/test/test_helper.rb19
78 files changed, 323 insertions, 171 deletions
diff --git a/activestorage/README.md b/activestorage/README.md
index 957adc05c3..d4ffe0c484 100644
--- a/activestorage/README.md
+++ b/activestorage/README.md
@@ -83,14 +83,6 @@ Variation of image attachment:
<%= image_tag user.avatar.variant(resize: "100x100") %>
```
-## Installation
-
-1. Run `rails activestorage:install` to create needed directories, migrations, and configuration.
-2. Optional: Add `gem "aws-sdk", "~> 2"` to your Gemfile if you want to use AWS S3.
-3. Optional: Add `gem "google-cloud-storage", "~> 1.3"` to your Gemfile if you want to use Google Cloud Storage.
-4. Optional: Add `gem "azure-storage"` to your Gemfile if you want to use Microsoft Azure.
-5. Optional: Add `gem "mini_magick"` to your Gemfile if you want to use variants.
-
## Direct uploads
Active Storage, with its included JavaScript library, supports uploading directly from the client to the cloud.
diff --git a/activestorage/Rakefile b/activestorage/Rakefile
index a41e07f373..aa71a65f6e 100644
--- a/activestorage/Rakefile
+++ b/activestorage/Rakefile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "bundler/setup"
require "bundler/gem_tasks"
require "rake/testtask"
diff --git a/activestorage/app/controllers/active_storage/blobs_controller.rb b/activestorage/app/controllers/active_storage/blobs_controller.rb
index 05af29f8b2..00aa8567c8 100644
--- a/activestorage/app/controllers/active_storage/blobs_controller.rb
+++ b/activestorage/app/controllers/active_storage/blobs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Take a signed permanent reference for a blob and turn it into an expiring service URL for download.
# 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
@@ -5,6 +7,7 @@
class ActiveStorage::BlobsController < ActionController::Base
def show
if blob = find_signed_blob
+ expires_in 5.minutes # service_url defaults to 5 minutes
redirect_to blob.service_url(disposition: disposition_param)
else
head :not_found
diff --git a/activestorage/app/controllers/active_storage/direct_uploads_controller.rb b/activestorage/app/controllers/active_storage/direct_uploads_controller.rb
index 0d93985897..205d173648 100644
--- a/activestorage/app/controllers/active_storage/direct_uploads_controller.rb
+++ b/activestorage/app/controllers/active_storage/direct_uploads_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Creates a new blob on the server side in anticipation of a direct-to-service upload from the client side.
# When the client-side upload is completed, the signed_blob_id can be submitted as part of the form to reference
# the blob that was created up front.
diff --git a/activestorage/app/controllers/active_storage/disk_controller.rb b/activestorage/app/controllers/active_storage/disk_controller.rb
index 76377a0f20..b10d4e2cac 100644
--- a/activestorage/app/controllers/active_storage/disk_controller.rb
+++ b/activestorage/app/controllers/active_storage/disk_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Serves files stored with the disk service in the same way that the cloud services do.
# This means using expiring, signed URLs that are meant for immediate access, not permanent linking.
# Always go through the BlobsController, or your own authenticated controller, rather than directly
diff --git a/activestorage/app/controllers/active_storage/variants_controller.rb b/activestorage/app/controllers/active_storage/variants_controller.rb
index 994c57aafd..02e3010626 100644
--- a/activestorage/app/controllers/active_storage/variants_controller.rb
+++ b/activestorage/app/controllers/active_storage/variants_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Take a signed permanent reference for a variant and turn it into an expiring service URL for download.
# 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
@@ -5,6 +7,7 @@
class ActiveStorage::VariantsController < ActionController::Base
def show
if blob = find_signed_blob
+ expires_in 5.minutes # service_url defaults to 5 minutes
redirect_to ActiveStorage::Variant.new(blob, decoded_variation).processed.service_url(disposition: disposition_param)
else
head :not_found
diff --git a/activestorage/app/jobs/active_storage/purge_job.rb b/activestorage/app/jobs/active_storage/purge_job.rb
index 815f908e6c..404ccefd05 100644
--- a/activestorage/app/jobs/active_storage/purge_job.rb
+++ b/activestorage/app/jobs/active_storage/purge_job.rb
@@ -1,4 +1,6 @@
-# Provides delayed purging of attachments or blobs using their `#purge_later` method.
+# frozen_string_literal: true
+
+# Provides delayed purging of attachments or blobs using their +#purge_later+ method.
class ActiveStorage::PurgeJob < ActiveJob::Base
# FIXME: Limit this to a custom ActiveStorage error
retry_on StandardError
diff --git a/activestorage/app/models/active_storage/attachment.rb b/activestorage/app/models/active_storage/attachment.rb
index e94fc69bba..adfa6d4aa5 100644
--- a/activestorage/app/models/active_storage/attachment.rb
+++ b/activestorage/app/models/active_storage/attachment.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "active_support/core_ext/module/delegation"
# Attachments associate records with blobs. Usually that's a one record-many blobs relationship,
@@ -21,7 +23,7 @@ class ActiveStorage::Attachment < ActiveRecord::Base
# Purging an attachment means purging the blob, which means talking to the service, which means
# talking over the internet. Whenever you're doing that, it's a good idea to put that work in a job,
- # so it doesn't hold up other operations. That's what #purge_later provides.
+ # so it doesn't hold up other operations. That's what +#purge_later+ provides.
def purge_later
ActiveStorage::PurgeJob.perform_later(self)
end
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb
index c72073f9f6..dc91a9265f 100644
--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# A blob is a record that contains the metadata about a file and a key for where that file resides on the service.
# Blobs can be created in two ways:
#
@@ -29,7 +31,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
find ActiveStorage.verifier.verify(id, purpose: :blob_id)
end
- # Returns a new, unsaved blob instance after the `io` has been uploaded to the service.
+ # 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)
new.tap do |blob|
blob.filename = filename
@@ -40,8 +42,8 @@ class ActiveStorage::Blob < ActiveRecord::Base
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 doing to avoid opening a transaction and talking to
+ # 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 doing to avoid opening a transaction and talking to
# the service during that (which is a bad idea and leads to deadlocks).
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!)
@@ -72,7 +74,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
self[:key] ||= self.class.generate_unique_secure_token
end
- # Returns a `ActiveStorage::Filename` instance of the filename that can be queried for basename, extension, and
+ # Returns a ActiveStorage::Filename instance of the filename that can be queried for basename, extension, and
# a sanitized version of the filename that's safe to use in URLs.
def filename
ActiveStorage::Filename.new(self[:filename])
@@ -98,7 +100,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
content_type.start_with?("text")
end
- # Returns a `ActiveStorage::Variant` instance with the set of `transformations` passed in. This is only relevant
+ # Returns a ActiveStorage::Variant instance with the set of +transformations+ passed in. This is only relevant
# for image files, and it allows any image to be transformed for size, colors, and the like. Example:
#
# avatar.variant(resize: "100x100").processed.service_url
@@ -111,7 +113,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
#
# <%= image_tag url_for(Current.user.avatar.variant(resize: "100x100")) %>
#
- # This will create a URL for that specific blob with that specific variant, which the `ActiveStorage::VariantsController`
+ # This will create a URL for that specific blob with that specific variant, which the ActiveStorage::VariantsController
# can then produce on-demand.
def variant(transformations)
ActiveStorage::Variant.new(self, ActiveStorage::Variation.new(transformations))
@@ -119,9 +121,9 @@ class ActiveStorage::Blob < ActiveRecord::Base
# Returns the URL of the blob on the service. This URL is intended to be short-lived for security and not used directly
- # with users. Instead, the `service_url` should only be exposed as a redirect from a stable, possibly authenticated URL.
- # Hiding the `service_url` behind a redirect also gives you the power to change services without updating all URLs. And
- # it allows permanent URLs that redirect to the `service_url` to be cached in the view.
+ # with users. Instead, the +service_url+ should only be exposed as a redirect from a stable, possibly authenticated URL.
+ # Hiding the +service_url+ behind a redirect also gives you the power to change services without updating all URLs. And
+ # it allows permanent URLs that redirect to the +service_url+ to be cached in the view.
def service_url(expires_in: 5.minutes, disposition: :inline)
service.url key, expires_in: expires_in, disposition: disposition, filename: filename, content_type: content_type
end
@@ -132,21 +134,21 @@ class ActiveStorage::Blob < ActiveRecord::Base
service.url_for_direct_upload key, expires_in: expires_in, content_type: content_type, content_length: byte_size, checksum: checksum
end
- # Returns a Hash of headers for `service_url_for_direct_upload` requests.
+ # Returns a Hash of headers for +service_url_for_direct_upload+ requests.
def service_headers_for_direct_upload
service.headers_for_direct_upload key, filename: filename, content_type: content_type, content_length: byte_size, checksum: checksum
end
- # Uploads the `io` to the service on the `key` for this blob. Blobs are intended to be immutable, so you shouldn't be
+ # Uploads the +io+ to the service on the +key+ for this blob. Blobs are intended to be immutable, so you shouldn't be
# using this method after a file has already been uploaded to fit with a blob. If you want to create a derivative blob,
# you should instead simply create a new blob based on the old one.
#
# 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.
+ # 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.
#
- # 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!`.
+ # 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)
self.checksum = compute_checksum_in_chunks(io)
self.byte_size = io.size
@@ -162,7 +164,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
# Deletes the file on the service that's associated with this blob. This should only be done if the blob is going to be
- # deleted as well or you will essentially have a dead reference. It's recommended to use the `#purge` and `#purge_later`
+ # deleted as well or you will essentially have a dead reference. It's recommended to use the +#purge+ and +#purge_later+
# methods in most circumstances.
def delete
service.delete key
@@ -170,13 +172,13 @@ class ActiveStorage::Blob < ActiveRecord::Base
# Deletes the file on the service and then destroys the blob record. This is the recommended way to dispose of unwanted
# blobs. Note, though, that deleting the file off the service will initiate a HTTP connection to the service, which may
- # be slow or prevented, so you should not use this method inside a transaction or in callbacks. Use `#purge_later` instead.
+ # be slow or prevented, so you should not use this method inside a transaction or in callbacks. Use +#purge_later+ instead.
def purge
delete
destroy
end
- # Enqueues a `ActiveStorage::PurgeJob` job that'll call `#purge`. This is the recommended way to purge blobs when the call
+ # Enqueues a ActiveStorage::PurgeJob job that'll call +#purge+. This is the recommended way to purge blobs when the call
# needs to be made from a transaction, a callback, or any other real-time scenario.
def purge_later
ActiveStorage::PurgeJob.perform_later(self)
diff --git a/activestorage/app/models/active_storage/filename.rb b/activestorage/app/models/active_storage/filename.rb
index 35f4a8ac59..6a9889addf 100644
--- a/activestorage/app/models/active_storage/filename.rb
+++ b/activestorage/app/models/active_storage/filename.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Encapsulates a string representing a filename to provide convenience access to parts of it and a sanitized version.
# This is what's returned by `ActiveStorage::Blob#filename`. A Filename instance is comparable so it can be used for sorting.
class ActiveStorage::Filename
diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb
index e3f22bcb25..7b4ca18c8c 100644
--- a/activestorage/app/models/active_storage/variant.rb
+++ b/activestorage/app/models/active_storage/variant.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Image blobs can have variants that are the result of a set of transformations applied to the original.
# These variants are used to create thumbnails, fixed-size avatars, or any other derivative image from the
# original.
@@ -9,17 +11,17 @@
# into memory. The larger the image, the more memory is used. Because of this process, you also want to be
# considerate about when the variant is actually processed. You shouldn't be processing variants inline in a
# template, for example. Delay the processing to an on-demand controller, like the one provided in
-# `ActiveStorage::VariantsController`.
+# ActiveStorage::VariantsController.
#
# To refer to such a delayed on-demand variant, simply link to the variant through the resolved route provided
# by Active Storage like so:
#
# <%= image_tag url_for(Current.user.avatar.variant(resize: "100x100")) %>
#
-# This will create a URL for that specific blob with that specific variant, which the `ActiveStorage::VariantsController`
+# This will create a URL for that specific blob with that specific variant, which the ActiveStorage::VariantsController
# can then produce on-demand.
#
-# When you do want to actually produce the variant needed, call `#processed`. This will check that the variant
+# When you do want to actually produce the variant needed, call +#processed+. This will check that the variant
# has already been processed and uploaded to the service, and, if so, just return that. Otherwise it will perform
# the transformations, upload the variant to the service, and return itself again. Example:
#
@@ -52,12 +54,12 @@ class ActiveStorage::Variant
end
# Returns the URL of the variant on the service. This URL is intended to be short-lived for security and not used directly
- # with users. Instead, the `service_url` should only be exposed as a redirect from a stable, possibly authenticated URL.
- # Hiding the `service_url` behind a redirect also gives you the power to change services without updating all URLs. And
- # it allows permanent URLs that redirec to the `service_url` to be cached in the view.
+ # with users. Instead, the +service_url+ should only be exposed as a redirect from a stable, possibly authenticated URL.
+ # Hiding the +service_url+ behind a redirect also gives you the power to change services without updating all URLs. And
+ # it allows permanent URLs that redirect to the +service_url+ to be cached in the view.
#
# Use `url_for(variant)` (or the implied form, like `link_to variant` or `redirect_to variant`) to get the stable URL
- # for a variant that points to the `ActiveStorage::VariantsController`, which in turn will use this `#service_call` method
+ # for a variant that points to the ActiveStorage::VariantsController, which in turn will use this +#service_call+ method
# for its redirection.
def service_url(expires_in: 5.minutes, disposition: :inline)
service.url key, expires_in: expires_in, disposition: disposition, filename: blob.filename, content_type: blob.content_type
diff --git a/activestorage/app/models/active_storage/variation.rb b/activestorage/app/models/active_storage/variation.rb
index e784506b4c..396ce85ef1 100644
--- a/activestorage/app/models/active_storage/variation.rb
+++ b/activestorage/app/models/active_storage/variation.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "active_support/core_ext/object/inclusion"
# A set of transformations that can be applied to a blob to create a variant. This class is exposed via
@@ -13,12 +15,12 @@ class ActiveStorage::Variation
attr_reader :transformations
class << self
- # Returns a variation instance with the transformations that were encoded by `#encode`.
+ # Returns a variation instance with the transformations that were encoded by +#encode+.
def decode(key)
new ActiveStorage.verifier.verify(key, purpose: :variation)
end
- # Returns a signed key for the `transformations`, which can be used to refer to a specific
+ # Returns a signed key for the +transformations+, which can be used to refer to a specific
# variation in a URL or combined key (like `ActiveStorage::Variant#key`).
def encode(transformations)
ActiveStorage.verifier.generate(transformations, purpose: :variation)
@@ -30,7 +32,7 @@ class ActiveStorage::Variation
end
# Accepts an open MiniMagick image instance, like what's return by `MiniMagick::Image.read(io)`,
- # and performs the `transformations` against it. The transformed image instance is then returned.
+ # and performs the +transformations+ against it. The transformed image instance is then returned.
def transform(image)
transformations.each do |(method, argument)|
if eligible_argument?(argument)
@@ -41,7 +43,7 @@ class ActiveStorage::Variation
end
end
- # Returns a signed key for all the `transformations` that this variation was instantiated with.
+ # Returns a signed key for all the +transformations+ that this variation was instantiated with.
def key
self.class.encode(transformations)
end
diff --git a/activestorage/config/routes.rb b/activestorage/config/routes.rb
index fddbb93255..168788475c 100644
--- a/activestorage/config/routes.rb
+++ b/activestorage/config/routes.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
Rails.application.routes.draw do
get "/rails/active_storage/blobs/:signed_id/*filename" => "active_storage/blobs#show", as: :rails_service_blob
diff --git a/activestorage/db/migrate/20170806125915_create_active_storage_tables.rb b/activestorage/db/migrate/20170806125915_create_active_storage_tables.rb
new file mode 100644
index 0000000000..d333b6bf9c
--- /dev/null
+++ b/activestorage/db/migrate/20170806125915_create_active_storage_tables.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class CreateActiveStorageTables < ActiveRecord::Migration[5.1]
+ def change
+ create_table :active_storage_blobs do |t|
+ t.string :key, null: false
+ t.string :filename, null: false
+ t.string :content_type
+ t.text :metadata
+ t.integer :byte_size, null: false
+ t.string :checksum, null: false
+ t.datetime :created_at, null: false
+
+ t.index [ :key ], unique: true
+ end
+
+ create_table :active_storage_attachments do |t|
+ t.string :name, null: false
+ t.references :record, null: false, polymorphic: true, index: false
+ t.references :blob, null: false
+
+ t.datetime :created_at, null: false
+
+ t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
+ end
+ end
+end
diff --git a/activestorage/lib/active_storage.rb b/activestorage/lib/active_storage.rb
index 412f08e8f5..ccc1d4a163 100644
--- a/activestorage/lib/active_storage.rb
+++ b/activestorage/lib/active_storage.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
#--
# Copyright (c) 2017 David Heinemeier Hansson
#
diff --git a/activestorage/lib/active_storage/attached.rb b/activestorage/lib/active_storage/attached.rb
index 5ac8ba5377..e90b75afd0 100644
--- a/activestorage/lib/active_storage/attached.rb
+++ b/activestorage/lib/active_storage/attached.rb
@@ -1,9 +1,11 @@
+# frozen_string_literal: true
+
require "action_dispatch"
require "action_dispatch/http/upload"
require "active_support/core_ext/module/delegation"
module ActiveStorage
-# Abstract baseclass for the concrete `ActiveStorage::Attached::One` and `ActiveStorage::Attached::Many`
+# Abstract baseclass for the concrete ActiveStorage::Attached::One and ActiveStorage::Attached::Many
# classes that both provide proxy access to the blob association for a record.
class Attached
attr_reader :name, :record
@@ -17,7 +19,7 @@ module ActiveStorage
case attachable
when ActiveStorage::Blob
attachable
- when ActionDispatch::Http::UploadedFile
+ when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile
ActiveStorage::Blob.create_after_upload! \
io: attachable.open,
filename: attachable.original_filename,
diff --git a/activestorage/lib/active_storage/attached/macros.rb b/activestorage/lib/active_storage/attached/macros.rb
index 5779348148..027112195f 100644
--- a/activestorage/lib/active_storage/attached/macros.rb
+++ b/activestorage/lib/active_storage/attached/macros.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ActiveStorage
# Provides the class-level DSL for declaring that an Active Record model has attached blobs.
module Attached::Macros
@@ -10,25 +12,23 @@ module ActiveStorage
# There is no column defined on the model side, Active Storage takes
# care of the mapping between your records and the attachment.
#
- # Under the covers, this relationship is implemented as a `has_one` association to a
- # `ActiveStorage::Attachment` record and a `has_one-through` association to a
- # `ActiveStorage::Blob` record. These associations are available as `avatar_attachment`
- # and `avatar_blob`. But you shouldn't need to work with these associations directly in
+ # Under the covers, this relationship is implemented as a +has_one+ association to a
+ # ActiveStorage::Attachment record and a +has_one-through+ association to a
+ # ActiveStorage::Blob record. These associations are available as +avatar_attachment+
+ # and +avatar_blob+. But you shouldn't need to work with these associations directly in
# most circumstances.
#
- # The system has been designed to having you go through the `ActiveStorage::Attached::One`
- # proxy that provides the dynamic proxy to the associations and factory methods, like `#attach`.
+ # The system has been designed to having you go through the ActiveStorage::Attached::One
+ # proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+.
#
# If the +:dependent+ option isn't set, the attachment will be purged
# (i.e. destroyed) whenever the record is destroyed.
def has_one_attached(name, dependent: :purge_later)
- define_method(name) do
- if instance_variable_defined?("@active_storage_attached_#{name}")
- instance_variable_get("@active_storage_attached_#{name}")
- else
- instance_variable_set("@active_storage_attached_#{name}", ActiveStorage::Attached::One.new(name, self))
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name}
+ @active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self)
end
- end
+ CODE
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record
has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob
@@ -51,25 +51,23 @@ module ActiveStorage
#
# Gallery.where(user: Current.user).with_attached_photos
#
- # Under the covers, this relationship is implemented as a `has_many` association to a
- # `ActiveStorage::Attachment` record and a `has_many-through` association to a
- # `ActiveStorage::Blob` record. These associations are available as `photos_attachments`
- # and `photos_blobs`. But you shouldn't need to work with these associations directly in
+ # Under the covers, this relationship is implemented as a +has_many+ association to a
+ # ActiveStorage::Attachment record and a +has_many-through+ association to a
+ # ActiveStorage::Blob record. These associations are available as +photos_attachments+
+ # and +photos_blobs+. But you shouldn't need to work with these associations directly in
# most circumstances.
#
- # The system has been designed to having you go through the `ActiveStorage::Attached::Many`
- # proxy that provides the dynamic proxy to the associations and factory methods, like `#attach`.
+ # The system has been designed to having you go through the ActiveStorage::Attached::Many
+ # proxy that provides the dynamic proxy to the associations and factory methods, like +#attach+.
#
# If the +:dependent+ option isn't set, all the attachments will be purged
# (i.e. destroyed) whenever the record is destroyed.
def has_many_attached(name, dependent: :purge_later)
- define_method(name) do
- if instance_variable_defined?("@active_storage_attached_#{name}")
- instance_variable_get("@active_storage_attached_#{name}")
- else
- instance_variable_set("@active_storage_attached_#{name}", ActiveStorage::Attached::Many.new(name, self))
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name}
+ @active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self)
end
- end
+ CODE
has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment"
has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob
@@ -81,4 +79,4 @@ module ActiveStorage
end
end
end
-end \ No newline at end of file
+end
diff --git a/activestorage/lib/active_storage/attached/many.rb b/activestorage/lib/active_storage/attached/many.rb
index 82989e4605..59b7d7d559 100644
--- a/activestorage/lib/active_storage/attached/many.rb
+++ b/activestorage/lib/active_storage/attached/many.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ActiveStorage
# Decorated proxy object representing of multiple attachments to a model.
class Attached::Many < Attached
@@ -5,7 +7,7 @@ module ActiveStorage
# Returns all the associated attachment records.
#
- # All methods called on this proxy object that aren't listed here will automatically be delegated to `attachments`.
+ # All methods called on this proxy object that aren't listed here will automatically be delegated to +attachments+.
def attachments
record.public_send("#{name}_attachments")
end
@@ -51,4 +53,3 @@ module ActiveStorage
end
end
end
-
diff --git a/activestorage/lib/active_storage/attached/one.rb b/activestorage/lib/active_storage/attached/one.rb
index 6b34b30f1c..2e5831348e 100644
--- a/activestorage/lib/active_storage/attached/one.rb
+++ b/activestorage/lib/active_storage/attached/one.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ActiveStorage
# Representation of a single attachment to a model.
class Attached::One < Attached
diff --git a/activestorage/lib/active_storage/engine.rb b/activestorage/lib/active_storage/engine.rb
index da83d3908a..a5562b32d3 100644
--- a/activestorage/lib/active_storage/engine.rb
+++ b/activestorage/lib/active_storage/engine.rb
@@ -5,6 +5,8 @@ require "active_storage"
module ActiveStorage
class Engine < Rails::Engine # :nodoc:
+ isolate_namespace ActiveStorage
+
config.active_storage = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActiveStorage
@@ -34,22 +36,21 @@ module ActiveStorage
end
initializer "active_storage.services" do
- config.after_initialize do |app|
- if config_choice = app.config.active_storage.service
- config_file = Pathname.new(Rails.root.join("config/storage.yml"))
- raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist?
+ config.to_prepare do
+ if config_choice = Rails.configuration.active_storage.service
+ configs = Rails.configuration.active_storage.service_configurations ||= begin
+ config_file = Pathname.new(Rails.root.join("config/storage.yml"))
+ raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist?
- require "yaml"
- require "erb"
+ require "yaml"
+ require "erb"
- configs =
- begin
- YAML.load(ERB.new(config_file.read).result) || {}
- rescue Psych::SyntaxError => e
- raise "YAML syntax error occurred while parsing #{config_file}. " \
- "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
- "Error: #{e.message}"
- end
+ YAML.load(ERB.new(config_file.read).result) || {}
+ rescue Psych::SyntaxError => e
+ raise "YAML syntax error occurred while parsing #{config_file}. " \
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
+ "Error: #{e.message}"
+ end
ActiveStorage::Blob.service =
begin
diff --git a/activestorage/lib/active_storage/gem_version.rb b/activestorage/lib/active_storage/gem_version.rb
index db79c669bf..bb6241ae47 100644
--- a/activestorage/lib/active_storage/gem_version.rb
+++ b/activestorage/lib/active_storage/gem_version.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ActiveStorage
# Returns the version of the currently loaded Active Storage as a <tt>Gem::Version</tt>
def self.gem_version
diff --git a/activestorage/lib/active_storage/log_subscriber.rb b/activestorage/lib/active_storage/log_subscriber.rb
index 5c1b8d23ef..80cc5d5c80 100644
--- a/activestorage/lib/active_storage/log_subscriber.rb
+++ b/activestorage/lib/active_storage/log_subscriber.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
require "active_support/log_subscriber"
module ActiveStorage
class LogSubscriber < ActiveSupport::LogSubscriber
def service_upload(event)
message = "Uploaded file to key: #{key_in(event)}"
- message << " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
+ message += " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
info event, color(message, GREEN)
end
diff --git a/activestorage/lib/active_storage/migration.rb b/activestorage/lib/active_storage/migration.rb
deleted file mode 100644
index 2e35e163cd..0000000000
--- a/activestorage/lib/active_storage/migration.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class ActiveStorageCreateTables < ActiveRecord::Migration[5.1]
- def change
- create_table :active_storage_blobs do |t|
- t.string :key
- t.string :filename
- t.string :content_type
- t.text :metadata
- t.integer :byte_size
- t.string :checksum
- t.datetime :created_at
-
- t.index [ :key ], unique: true
- end
-
- create_table :active_storage_attachments do |t|
- t.string :name
- t.string :record_type
- t.integer :record_id
- t.integer :blob_id
-
- t.datetime :created_at
-
- t.index :blob_id
- t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
- end
- end
-end
diff --git a/activestorage/lib/active_storage/service.rb b/activestorage/lib/active_storage/service.rb
index eb25e9f001..ce736b8728 100644
--- a/activestorage/lib/active_storage/service.rb
+++ b/activestorage/lib/active_storage/service.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "active_storage/log_subscriber"
module ActiveStorage
@@ -59,43 +61,43 @@ module ActiveStorage
end
end
- # Upload the `io` to the `key` specified. If a `checksum` is provided, the service will
- # ensure a match when the upload has completed or raise an `ActiveStorage::IntegrityError`.
+ # Upload the +io+ to the +key+ specified. If a +checksum+ is provided, the service will
+ # ensure a match when the upload has completed or raise an ActiveStorage::IntegrityError.
def upload(key, io, checksum: nil)
raise NotImplementedError
end
- # Return the content of the file at the `key`.
+ # Return the content of the file at the +key+.
def download(key)
raise NotImplementedError
end
- # Delete the file at the `key`.
+ # Delete the file at the +key+.
def delete(key)
raise NotImplementedError
end
- # Return true if a file exists at the `key`.
+ # Return true if a file exists at the +key+.
def exist?(key)
raise NotImplementedError
end
- # Returns a signed, temporary URL for the file at the `key`. The URL will be valid for the amount
- # of seconds specified in `expires_in`. You most also provide the `disposition` (`:inline` or `:attachment`),
- # `filename`, and `content_type` that you wish the file to be served with on request.
+ # Returns a signed, temporary URL for the file at the +key+. The URL will be valid for the amount
+ # of seconds specified in +expires_in+. You most also provide the +disposition+ (+:inline+ or +:attachment+),
+ # +filename+, and +content_type+ that you wish the file to be served with on request.
def url(key, expires_in:, disposition:, filename:, content_type:)
raise NotImplementedError
end
- # Returns a signed, temporary URL that a direct upload file can be PUT to on the `key`.
- # The URL will be valid for the amount of seconds specified in `expires_in`.
- # You most also provide the `content_type`, `content_length`, and `checksum` of the file
+ # Returns a signed, temporary URL that a direct upload file can be PUT to on the +key+.
+ # The URL will be valid for the amount of seconds specified in +expires_in+.
+ # You most also provide the +content_type+, +content_length+, and +checksum+ of the file
# that will be uploaded. All these attributes will be validated by the service upon upload.
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
raise NotImplementedError
end
- # Returns a Hash of headers for `url_for_direct_upload` requests.
+ # Returns a Hash of headers for +url_for_direct_upload+ requests.
def headers_for_direct_upload(key, filename:, content_type:, content_length:, checksum:)
{}
end
diff --git a/activestorage/lib/active_storage/service/azure_storage_service.rb b/activestorage/lib/active_storage/service/azure_storage_service.rb
index c2e1b25a43..d066deaa20 100644
--- a/activestorage/lib/active_storage/service/azure_storage_service.rb
+++ b/activestorage/lib/active_storage/service/azure_storage_service.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
require "active_support/core_ext/numeric/bytes"
require "azure/storage"
require "azure/storage/core/auth/shared_access_signature"
module ActiveStorage
# Wraps the Microsoft Azure Storage Blob Service as a Active Storage service.
- # See `ActiveStorage::Service` for the generic API documentation that applies to all services.
+ # See ActiveStorage::Service for the generic API documentation that applies to all services.
class Service::AzureStorageService < Service
attr_reader :client, :path, :blobs, :container, :signer
@@ -57,11 +59,12 @@ module ActiveStorage
end
end
- def url(key, expires_in:, disposition:, filename:)
+ def url(key, expires_in:, disposition:, filename:, content_type:)
instrument :url, key do |payload|
base_url = url_for(key)
generated_url = signer.signed_uri(URI(base_url), false, permissions: "r",
- expiry: format_expiry(expires_in), content_disposition: "#{disposition}; filename=\"#{filename}\"").to_s
+ expiry: format_expiry(expires_in), content_type: content_type,
+ content_disposition: "#{disposition}; filename=\"#{filename}\"").to_s
payload[:url] = generated_url
diff --git a/activestorage/lib/active_storage/service/configurator.rb b/activestorage/lib/active_storage/service/configurator.rb
index 5d6475a8ae..39951fd026 100644
--- a/activestorage/lib/active_storage/service/configurator.rb
+++ b/activestorage/lib/active_storage/service/configurator.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ActiveStorage
class Service::Configurator #:nodoc:
attr_reader :configurations
diff --git a/activestorage/lib/active_storage/service/disk_service.rb b/activestorage/lib/active_storage/service/disk_service.rb
index 3d92102cf0..cf4019966f 100644
--- a/activestorage/lib/active_storage/service/disk_service.rb
+++ b/activestorage/lib/active_storage/service/disk_service.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
require "fileutils"
require "pathname"
require "digest/md5"
require "active_support/core_ext/numeric/bytes"
module ActiveStorage
- # Wraps a local disk path as a Active Storage service. See `ActiveStorage::Service` for the generic API
+ # Wraps a local disk path as a Active Storage service. See ActiveStorage::Service for the generic API
# documentation that applies to all services.
class Service::DiskService < Service
attr_reader :root
@@ -124,4 +126,3 @@ module ActiveStorage
end
end
end
-
diff --git a/activestorage/lib/active_storage/service/gcs_service.rb b/activestorage/lib/active_storage/service/gcs_service.rb
index ea4ec5a790..32dfb4851b 100644
--- a/activestorage/lib/active_storage/service/gcs_service.rb
+++ b/activestorage/lib/active_storage/service/gcs_service.rb
@@ -1,8 +1,10 @@
+# frozen_string_literal: true
+
require "google/cloud/storage"
require "active_support/core_ext/object/to_query"
module ActiveStorage
- # Wraps the Google Cloud Storage as a Active Storage service. See `ActiveStorage::Service` for the generic API
+ # Wraps the Google Cloud Storage as a Active Storage service. See ActiveStorage::Service for the generic API
# documentation that applies to all services.
class Service::GCSService < Service
attr_reader :client, :bucket
diff --git a/activestorage/lib/active_storage/service/mirror_service.rb b/activestorage/lib/active_storage/service/mirror_service.rb
index 2403eeb1e9..39e922f7ab 100644
--- a/activestorage/lib/active_storage/service/mirror_service.rb
+++ b/activestorage/lib/active_storage/service/mirror_service.rb
@@ -1,9 +1,11 @@
+# frozen_string_literal: true
+
require "active_support/core_ext/module/delegation"
module ActiveStorage
- # Wraps a set of mirror services and provides a single `ActiveStorage::Service` object that will all
- # have the files uploaded to them. A `primary` service is designated to answer calls to `download`, `exists?`,
- # and `url`.
+ # Wraps a set of mirror services and provides a single ActiveStorage::Service object that will all
+ # have the files uploaded to them. A +primary+ service is designated to answer calls to +download+, +exists?+,
+ # and +url+.
class Service::MirrorService < Service
attr_reader :primary, :mirrors
@@ -20,15 +22,15 @@ module ActiveStorage
@primary, @mirrors = primary, mirrors
end
- # Upload the `io` to the `key` specified to all services. If a `checksum` is provided, all services will
- # ensure a match when the upload has completed or raise an `ActiveStorage::IntegrityError`.
+ # Upload the +io+ to the +key+ specified to all services. If a +checksum+ is provided, all services will
+ # ensure a match when the upload has completed or raise an ActiveStorage::IntegrityError.
def upload(key, io, checksum: nil)
each_service.collect do |service|
service.upload key, io.tap(&:rewind), checksum: checksum
end
end
- # Delete the file at the `key` on all services.
+ # Delete the file at the +key+ on all services.
def delete(key)
perform_across_services :delete, key
end
diff --git a/activestorage/lib/active_storage/service/s3_service.rb b/activestorage/lib/active_storage/service/s3_service.rb
index 5153f5db0d..98c9dd2972 100644
--- a/activestorage/lib/active_storage/service/s3_service.rb
+++ b/activestorage/lib/active_storage/service/s3_service.rb
@@ -1,9 +1,11 @@
+# frozen_string_literal: true
+
require "aws-sdk"
require "active_support/core_ext/numeric/bytes"
module ActiveStorage
# Wraps the Amazon Simple Storage Service (S3) as a Active Storage service.
- # See `ActiveStorage::Service` for the generic API documentation that applies to all services.
+ # See ActiveStorage::Service for the generic API documentation that applies to all services.
class Service::S3Service < Service
attr_reader :client, :bucket, :upload_options
diff --git a/activestorage/lib/active_storage/version.rb b/activestorage/lib/active_storage/version.rb
index 8f45480712..4b6631832b 100644
--- a/activestorage/lib/active_storage/version.rb
+++ b/activestorage/lib/active_storage/version.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative "gem_version"
module ActiveStorage
diff --git a/activestorage/lib/tasks/activestorage.rake b/activestorage/lib/tasks/activestorage.rake
index 1d386e67df..746bc5b28a 100644
--- a/activestorage/lib/tasks/activestorage.rake
+++ b/activestorage/lib/tasks/activestorage.rake
@@ -1,13 +1,8 @@
-require "fileutils"
+# frozen_string_literal: true
namespace :activestorage do
desc "Copy over the migration needed to the application"
- task :install do
- migration_file_path = "db/migrate/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_active_storage_create_tables.rb"
- FileUtils.mkdir_p Rails.root.join("db/migrate")
- FileUtils.cp File.expand_path("../../active_storage/migration.rb", __FILE__), Rails.root.join(migration_file_path)
- puts "Copied migration to #{migration_file_path}"
-
- puts "Now run rails db:migrate to create the tables for Active Storage"
+ task install: :environment do
+ Rake::Task["active_storage:install:migrations"].invoke
end
end
diff --git a/activestorage/test/controllers/blobs_controller_test.rb b/activestorage/test/controllers/blobs_controller_test.rb
new file mode 100644
index 0000000000..d682893e1d
--- /dev/null
+++ b/activestorage/test/controllers/blobs_controller_test.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "database/setup"
+
+class ActiveStorage::BlobsControllerTest < ActionDispatch::IntegrationTest
+ setup do
+ @blob = create_image_blob filename: "racecar.jpg"
+ end
+
+ test "showing blob utilizes browser caching" do
+ get rails_blob_url(@blob)
+
+ assert_redirected_to(/racecar.jpg/)
+ assert_equal "max-age=300, private", @response.headers["Cache-Control"]
+ end
+end
diff --git a/activestorage/test/controllers/direct_uploads_controller_test.rb b/activestorage/test/controllers/direct_uploads_controller_test.rb
index 4f335c7759..888767086c 100644
--- a/activestorage/test/controllers/direct_uploads_controller_test.rb
+++ b/activestorage/test/controllers/direct_uploads_controller_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "test_helper"
require "database/setup"
diff --git a/activestorage/test/controllers/disk_controller_test.rb b/activestorage/test/controllers/disk_controller_test.rb
index df7954d6b4..53a086f214 100644
--- a/activestorage/test/controllers/disk_controller_test.rb
+++ b/activestorage/test/controllers/disk_controller_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "test_helper"
require "database/setup"
diff --git a/activestorage/test/controllers/variants_controller_test.rb b/activestorage/test/controllers/variants_controller_test.rb
index b3ff83e95e..d9a85e16d9 100644
--- a/activestorage/test/controllers/variants_controller_test.rb
+++ b/activestorage/test/controllers/variants_controller_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "test_helper"
require "database/setup"
diff --git a/activestorage/test/database/create_users_migration.rb b/activestorage/test/database/create_users_migration.rb
index a0b72a90ee..317daa87b5 100644
--- a/activestorage/test/database/create_users_migration.rb
+++ b/activestorage/test/database/create_users_migration.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ActiveStorageCreateUsers < ActiveRecord::Migration[5.1]
def change
create_table :users do |t|
diff --git a/activestorage/test/database/setup.rb b/activestorage/test/database/setup.rb
index b12038ee68..87564499e6 100644
--- a/activestorage/test/database/setup.rb
+++ b/activestorage/test/database/setup.rb
@@ -1,6 +1,7 @@
-require "active_storage/migration"
+# frozen_string_literal: true
+
require_relative "create_users_migration"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
-ActiveStorageCreateTables.migrate(:up)
+ActiveRecord::Migrator.migrate File.expand_path("../../../db/migrate", __FILE__)
ActiveStorageCreateUsers.migrate(:up)
diff --git a/activestorage/test/dummy/Rakefile b/activestorage/test/dummy/Rakefile
index d1baef0699..c4f9523878 100644
--- a/activestorage/test/dummy/Rakefile
+++ b/activestorage/test/dummy/Rakefile
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative "config/application"
Rails.application.load_tasks
diff --git a/activestorage/test/dummy/app/controllers/application_controller.rb b/activestorage/test/dummy/app/controllers/application_controller.rb
index 1c07694e9d..280cc28ce2 100644
--- a/activestorage/test/dummy/app/controllers/application_controller.rb
+++ b/activestorage/test/dummy/app/controllers/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
diff --git a/activestorage/test/dummy/app/helpers/application_helper.rb b/activestorage/test/dummy/app/helpers/application_helper.rb
index de6be7945c..15b06f0f67 100644
--- a/activestorage/test/dummy/app/helpers/application_helper.rb
+++ b/activestorage/test/dummy/app/helpers/application_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
module ApplicationHelper
end
diff --git a/activestorage/test/dummy/app/jobs/application_job.rb b/activestorage/test/dummy/app/jobs/application_job.rb
index a009ace51c..d92ffddcb5 100644
--- a/activestorage/test/dummy/app/jobs/application_job.rb
+++ b/activestorage/test/dummy/app/jobs/application_job.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
class ApplicationJob < ActiveJob::Base
end
diff --git a/activestorage/test/dummy/app/models/application_record.rb b/activestorage/test/dummy/app/models/application_record.rb
index 10a4cba84d..71fbba5b32 100644
--- a/activestorage/test/dummy/app/models/application_record.rb
+++ b/activestorage/test/dummy/app/models/application_record.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
diff --git a/activestorage/test/dummy/bin/bundle b/activestorage/test/dummy/bin/bundle
index fe1874509a..277e128251 100755
--- a/activestorage/test/dummy/bin/bundle
+++ b/activestorage/test/dummy/bin/bundle
@@ -1,3 +1,5 @@
#!/usr/bin/env ruby
+# frozen_string_literal: true
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
load Gem.bin_path("bundler", "bundle")
diff --git a/activestorage/test/dummy/bin/rails b/activestorage/test/dummy/bin/rails
index efc0377492..22f2d8deee 100755
--- a/activestorage/test/dummy/bin/rails
+++ b/activestorage/test/dummy/bin/rails
@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
+# frozen_string_literal: true
+
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"
diff --git a/activestorage/test/dummy/bin/rake b/activestorage/test/dummy/bin/rake
index 4fbf10b960..e436ea54a1 100755
--- a/activestorage/test/dummy/bin/rake
+++ b/activestorage/test/dummy/bin/rake
@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
+# frozen_string_literal: true
+
require_relative "../config/boot"
require "rake"
Rake.application.run
diff --git a/activestorage/test/dummy/bin/yarn b/activestorage/test/dummy/bin/yarn
index b8fe4eeaf3..c9b7498378 100755
--- a/activestorage/test/dummy/bin/yarn
+++ b/activestorage/test/dummy/bin/yarn
@@ -1,4 +1,6 @@
#!/usr/bin/env ruby
+# frozen_string_literal: true
+
VENDOR_PATH = File.expand_path("..", __dir__)
Dir.chdir(VENDOR_PATH) do
begin
diff --git a/activestorage/test/dummy/config.ru b/activestorage/test/dummy/config.ru
index 441e6ff0c3..bff88d608a 100644
--- a/activestorage/test/dummy/config.ru
+++ b/activestorage/test/dummy/config.ru
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"
diff --git a/activestorage/test/dummy/config/application.rb b/activestorage/test/dummy/config/application.rb
index 5c59401358..7ee6625bb5 100644
--- a/activestorage/test/dummy/config/application.rb
+++ b/activestorage/test/dummy/config/application.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require_relative "boot"
require "rails"
diff --git a/activestorage/test/dummy/config/boot.rb b/activestorage/test/dummy/config/boot.rb
index 116591a4ed..59459d4ae3 100644
--- a/activestorage/test/dummy/config/boot.rb
+++ b/activestorage/test/dummy/config/boot.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Set up gems listed in the Gemfile.
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)
diff --git a/activestorage/test/dummy/config/environment.rb b/activestorage/test/dummy/config/environment.rb
index cac5315775..7df99e89c6 100644
--- a/activestorage/test/dummy/config/environment.rb
+++ b/activestorage/test/dummy/config/environment.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Load the Rails application.
require_relative "application"
diff --git a/activestorage/test/dummy/config/environments/development.rb b/activestorage/test/dummy/config/environments/development.rb
index 5f3d463210..47fc5bf25c 100644
--- a/activestorage/test/dummy/config/environments/development.rb
+++ b/activestorage/test/dummy/config/environments/development.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
diff --git a/activestorage/test/dummy/config/environments/production.rb b/activestorage/test/dummy/config/environments/production.rb
index 343da23f0b..34ac3bc561 100644
--- a/activestorage/test/dummy/config/environments/production.rb
+++ b/activestorage/test/dummy/config/environments/production.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
diff --git a/activestorage/test/dummy/config/environments/test.rb b/activestorage/test/dummy/config/environments/test.rb
index 4f2c048600..ce0889e8ae 100644
--- a/activestorage/test/dummy/config/environments/test.rb
+++ b/activestorage/test/dummy/config/environments/test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
diff --git a/activestorage/test/dummy/config/initializers/application_controller_renderer.rb b/activestorage/test/dummy/config/initializers/application_controller_renderer.rb
index 51639b67a0..315ac48a9a 100644
--- a/activestorage/test/dummy/config/initializers/application_controller_renderer.rb
+++ b/activestorage/test/dummy/config/initializers/application_controller_renderer.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# ApplicationController.renderer.defaults.merge!(
diff --git a/activestorage/test/dummy/config/initializers/assets.rb b/activestorage/test/dummy/config/initializers/assets.rb
index c1f948d018..ba194685a2 100644
--- a/activestorage/test/dummy/config/initializers/assets.rb
+++ b/activestorage/test/dummy/config/initializers/assets.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
diff --git a/activestorage/test/dummy/config/initializers/backtrace_silencers.rb b/activestorage/test/dummy/config/initializers/backtrace_silencers.rb
index 59385cdf37..d0f0d3b5df 100644
--- a/activestorage/test/dummy/config/initializers/backtrace_silencers.rb
+++ b/activestorage/test/dummy/config/initializers/backtrace_silencers.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
diff --git a/activestorage/test/dummy/config/initializers/cookies_serializer.rb b/activestorage/test/dummy/config/initializers/cookies_serializer.rb
index 5a6a32d371..ee8dff9c99 100644
--- a/activestorage/test/dummy/config/initializers/cookies_serializer.rb
+++ b/activestorage/test/dummy/config/initializers/cookies_serializer.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Be sure to restart your server when you modify this file.
# Specify a serializer for the signed and encrypted cookie jars.
diff --git a/activestorage/test/dummy/config/initializers/filter_parameter_logging.rb b/activestorage/test/dummy/config/initializers/filter_parameter_logging.rb
index 4a994e1e7b..7a4f47b4c2 100644
--- a/activestorage/test/dummy/config/initializers/filter_parameter_logging.rb
+++ b/activestorage/test/dummy/config/initializers/filter_parameter_logging.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
diff --git a/activestorage/test/dummy/config/initializers/inflections.rb b/activestorage/test/dummy/config/initializers/inflections.rb
index ac033bf9dc..aa7435fbc9 100644
--- a/activestorage/test/dummy/config/initializers/inflections.rb
+++ b/activestorage/test/dummy/config/initializers/inflections.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
diff --git a/activestorage/test/dummy/config/initializers/mime_types.rb b/activestorage/test/dummy/config/initializers/mime_types.rb
index dc1899682b..6e1d16f027 100644
--- a/activestorage/test/dummy/config/initializers/mime_types.rb
+++ b/activestorage/test/dummy/config/initializers/mime_types.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
diff --git a/activestorage/test/dummy/config/initializers/wrap_parameters.rb b/activestorage/test/dummy/config/initializers/wrap_parameters.rb
index bbfc3961bf..2f3c0db471 100644
--- a/activestorage/test/dummy/config/initializers/wrap_parameters.rb
+++ b/activestorage/test/dummy/config/initializers/wrap_parameters.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
diff --git a/activestorage/test/dummy/config/routes.rb b/activestorage/test/dummy/config/routes.rb
index 1daf9a4121..edf04d2d63 100644
--- a/activestorage/test/dummy/config/routes.rb
+++ b/activestorage/test/dummy/config/routes.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
Rails.application.routes.draw do
end
diff --git a/activestorage/test/dummy/config/spring.rb b/activestorage/test/dummy/config/spring.rb
index c9119b40c0..ff5ba06b6d 100644
--- a/activestorage/test/dummy/config/spring.rb
+++ b/activestorage/test/dummy/config/spring.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
%w(
.ruby-version
.rbenv-vars
diff --git a/activestorage/test/filename_test.rb b/activestorage/test/filename_test.rb
index e448238675..f1e4a467ba 100644
--- a/activestorage/test/filename_test.rb
+++ b/activestorage/test/filename_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "test_helper"
class ActiveStorage::FilenameTest < ActiveSupport::TestCase
@@ -10,8 +12,8 @@ class ActiveStorage::FilenameTest < ActiveSupport::TestCase
end
test "sanitize transcodes to valid UTF-8" do
- { "\xF6".force_encoding(Encoding::ISO8859_1) => "ö",
- "\xC3".force_encoding(Encoding::ISO8859_1) => "Ã",
+ { "\xF6".dup.force_encoding(Encoding::ISO8859_1) => "ö",
+ "\xC3".dup.force_encoding(Encoding::ISO8859_1) => "Ã",
"\xAD" => "�",
"\xCF" => "�",
"\x00" => "",
diff --git a/activestorage/test/models/attachments_test.rb b/activestorage/test/models/attachments_test.rb
index 82256e1f44..7cfd8683db 100644
--- a/activestorage/test/models/attachments_test.rb
+++ b/activestorage/test/models/attachments_test.rb
@@ -1,13 +1,8 @@
+# frozen_string_literal: true
+
require "test_helper"
require "database/setup"
-# ActiveRecord::Base.logger = Logger.new(STDOUT)
-
-class User < ActiveRecord::Base
- has_one_attached :avatar
- has_many_attached :highlights
-end
-
class ActiveStorage::AttachmentsTest < ActiveSupport::TestCase
include ActiveJob::TestHelper
@@ -25,11 +20,17 @@ class ActiveStorage::AttachmentsTest < ActiveSupport::TestCase
assert_equal "funky.jpg", @user.avatar.filename.to_s
end
- test "attach new blob" do
+ test "attach new blob from a Hash" do
@user.avatar.attach io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg"
assert_equal "town.jpg", @user.avatar.filename.to_s
end
+ test "attach new blob from an UploadedFile" do
+ file = file_fixture "racecar.jpg"
+ @user.avatar.attach Rack::Test::UploadedFile.new file
+ assert_equal "racecar.jpg", @user.avatar.filename.to_s
+ end
+
test "access underlying associations of new blob" do
@user.avatar.attach create_blob(filename: "funky.jpg")
assert_equal @user, @user.avatar_attachment.record
diff --git a/activestorage/test/models/blob_test.rb b/activestorage/test/models/blob_test.rb
index 8b14bcec87..1c50d18994 100644
--- a/activestorage/test/models/blob_test.rb
+++ b/activestorage/test/models/blob_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "test_helper"
require "database/setup"
diff --git a/activestorage/test/models/variant_test.rb b/activestorage/test/models/variant_test.rb
index 04ebaccb6a..f4e1e9e51d 100644
--- a/activestorage/test/models/variant_test.rb
+++ b/activestorage/test/models/variant_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "test_helper"
require "database/setup"
diff --git a/activestorage/test/service/azure_storage_service_test.rb b/activestorage/test/service/azure_storage_service_test.rb
index e2be510b60..dac154cf11 100644
--- a/activestorage/test/service/azure_storage_service_test.rb
+++ b/activestorage/test/service/azure_storage_service_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "service/shared_service_tests"
require "uri"
@@ -6,8 +8,15 @@ if SERVICE_CONFIGURATIONS[:azure]
SERVICE = ActiveStorage::Service.configure(:azure, SERVICE_CONFIGURATIONS)
include ActiveStorage::Service::SharedServiceTests
- end
+ test "signed URL generation" do
+ url = @service.url(FIXTURE_KEY, expires_in: 5.minutes,
+ disposition: :inline, filename: "avatar.png", content_type: "image/png")
+
+ assert_match(/(\S+)&rsct=image%2Fpng&rscd=inline%3B\+filename%3D%22avatar.png/, url)
+ assert_match SERVICE_CONFIGURATIONS[:azure][:container], url
+ end
+ end
else
puts "Skipping Azure Storage Service tests because no Azure configuration was supplied"
end
diff --git a/activestorage/test/service/configurations.yml b/activestorage/test/service/configurations.yml
index d7aa672573..56ed37be5d 100644
--- a/activestorage/test/service/configurations.yml
+++ b/activestorage/test/service/configurations.yml
@@ -1,10 +1,10 @@
-s3:
- service: S3
- access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
- secret_access_key: <%= ENV["AWS_SECRET_KEY"] %>
- region: us-east-2
- bucket: rails-ci-activestorage
-
+# s3:
+# service: S3
+# access_key_id: ""
+# secret_access_key: ""
+# region: ""
+# bucket: ""
+#
# gcs:
# service: GCS
# keyfile: {
diff --git a/activestorage/test/service/configurator_test.rb b/activestorage/test/service/configurator_test.rb
index c69b8d5087..a2fd035e02 100644
--- a/activestorage/test/service/configurator_test.rb
+++ b/activestorage/test/service/configurator_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "service/shared_service_tests"
class ActiveStorage::Service::ConfiguratorTest < ActiveSupport::TestCase
diff --git a/activestorage/test/service/disk_service_test.rb b/activestorage/test/service/disk_service_test.rb
index 2fdb113616..835a3a2971 100644
--- a/activestorage/test/service/disk_service_test.rb
+++ b/activestorage/test/service/disk_service_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "service/shared_service_tests"
class ActiveStorage::Service::DiskServiceTest < ActiveSupport::TestCase
diff --git a/activestorage/test/service/gcs_service_test.rb b/activestorage/test/service/gcs_service_test.rb
index 03048731bc..5f53f61baf 100644
--- a/activestorage/test/service/gcs_service_test.rb
+++ b/activestorage/test/service/gcs_service_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "service/shared_service_tests"
require "net/http"
diff --git a/activestorage/test/service/mirror_service_test.rb b/activestorage/test/service/mirror_service_test.rb
index 129e11d06f..93e86eff70 100644
--- a/activestorage/test/service/mirror_service_test.rb
+++ b/activestorage/test/service/mirror_service_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "service/shared_service_tests"
class ActiveStorage::Service::MirrorServiceTest < ActiveSupport::TestCase
diff --git a/activestorage/test/service/s3_service_test.rb b/activestorage/test/service/s3_service_test.rb
index 57e13e6538..98f520741d 100644
--- a/activestorage/test/service/s3_service_test.rb
+++ b/activestorage/test/service/s3_service_test.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "service/shared_service_tests"
require "net/http"
diff --git a/activestorage/test/service/shared_service_tests.rb b/activestorage/test/service/shared_service_tests.rb
index 07620d91e4..a9e1cb6ce9 100644
--- a/activestorage/test/service/shared_service_tests.rb
+++ b/activestorage/test/service/shared_service_tests.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "test_helper"
require "active_support/core_ext/securerandom"
@@ -5,7 +7,7 @@ module ActiveStorage::Service::SharedServiceTests
extend ActiveSupport::Concern
FIXTURE_KEY = SecureRandom.base58(24)
- FIXTURE_DATA = "\211PNG\r\n\032\n\000\000\000\rIHDR\000\000\000\020\000\000\000\020\001\003\000\000\000%=m\"\000\000\000\006PLTE\000\000\000\377\377\377\245\331\237\335\000\000\0003IDATx\234c\370\377\237\341\377_\206\377\237\031\016\2603\334?\314p\1772\303\315\315\f7\215\031\356\024\203\320\275\317\f\367\201R\314\f\017\300\350\377\177\000Q\206\027(\316]\233P\000\000\000\000IEND\256B`\202".force_encoding(Encoding::BINARY)
+ FIXTURE_DATA = "\211PNG\r\n\032\n\000\000\000\rIHDR\000\000\000\020\000\000\000\020\001\003\000\000\000%=m\"\000\000\000\006PLTE\000\000\000\377\377\377\245\331\237\335\000\000\0003IDATx\234c\370\377\237\341\377_\206\377\237\031\016\2603\334?\314p\1772\303\315\315\f7\215\031\356\024\203\320\275\317\f\367\201R\314\f\017\300\350\377\177\000Q\206\027(\316]\233P\000\000\000\000IEND\256B`\202".dup.force_encoding(Encoding::BINARY)
included do
setup do
diff --git a/activestorage/test/template/image_tag_test.rb b/activestorage/test/template/image_tag_test.rb
index 83c95c01a1..46dd97b3e9 100644
--- a/activestorage/test/template/image_tag_test.rb
+++ b/activestorage/test/template/image_tag_test.rb
@@ -1,10 +1,8 @@
+# frozen_string_literal: true
+
require "test_helper"
require "database/setup"
-class User < ActiveRecord::Base
- has_one_attached :avatar
-end
-
class ActiveStorage::ImageTagTest < ActionView::TestCase
tests ActionView::Helpers::AssetTagHelper
diff --git a/activestorage/test/test_helper.rb b/activestorage/test/test_helper.rb
index 5b6d3b64c2..0bb3a925b8 100644
--- a/activestorage/test/test_helper.rb
+++ b/activestorage/test/test_helper.rb
@@ -1,16 +1,24 @@
+# frozen_string_literal: true
+
require File.expand_path("../../test/dummy/config/environment.rb", __FILE__)
require "bundler/setup"
require "active_support"
require "active_support/test_case"
require "active_support/testing/autorun"
-require "byebug"
+
+begin
+ require "byebug"
+rescue LoadError
+end
require "active_job"
ActiveJob::Base.queue_adapter = :test
-ActiveJob::Base.logger = nil
+ActiveJob::Base.logger = ActiveSupport::Logger.new(nil)
-require "active_storage"
+# Filter out Minitest backtrace while allowing backtrace from other libraries
+# to be shown.
+Minitest.backtrace_filter = Minitest::BacktraceFilter.new
require "yaml"
SERVICE_CONFIGURATIONS = begin
@@ -54,3 +62,8 @@ end
require "global_id"
GlobalID.app = "ActiveStorageExampleApp"
ActiveRecord::Base.send :include, GlobalID::Identification
+
+class User < ActiveRecord::Base
+ has_one_attached :avatar
+ has_many_attached :highlights
+end