diff options
Diffstat (limited to 'activestorage')
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 |