presigned_upload 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 651464bf9650c6acb0cbd6da5f0d3e1cb41bcf16c2825e32a64fd102e214917b
4
+ data.tar.gz: e07b382fd743b259a3196912dbb19eff4069e55381e20eb7b9a20f622b20aa88
5
+ SHA512:
6
+ metadata.gz: 8b7f57130a706d1d5651652134b152cf51a4dcd6442382c8c608d22d2b3af1380048f6bca891a811559cc94f7bc892a017170962ea23f92f6d2149ccf98ea066
7
+ data.tar.gz: 9329538342ea4ae88cd2b571e92c6cc87512a2f8f455cf6332267768ebdc9d170da6daed49bad15ad276cf77d801d3210076b82fdb07c1bbaae1dae17598fded
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,28 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+ Exclude:
4
+ - "lib/generators/**/templates/*"
5
+ NewCops: disable
6
+
7
+ Style/Documentation:
8
+ Enabled: true
9
+ Exclude:
10
+ - "lib/generators/presigned_upload/**"
11
+ - "spec/support/storage/*"
12
+ - "spec/support/*"
13
+
14
+ Style/StringLiterals:
15
+ Enabled: true
16
+ EnforcedStyle: double_quotes
17
+
18
+ Style/StringLiteralsInInterpolation:
19
+ Enabled: true
20
+ EnforcedStyle: double_quotes
21
+
22
+ Layout/LineLength:
23
+ Max: 120
24
+
25
+ Metrics/BlockLength:
26
+ Enabled: true
27
+ Exclude:
28
+ - "spec/**/*"
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2023-11-23
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in presigned_upload.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Denis Stael
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # PresignedUpload
2
+
3
+ Gem designed to control file uploads via presigned URLs to cloud storage services.
4
+
5
+ A presigned URL is generated by a server that grants temporary and controlled access to a specific resource. In the context of file uploads, it allows clients to directly upload files to a designated storage location without the server being directly involved in the transfer process.
6
+
7
+ ## Installation
8
+
9
+ Add this to your Gemfile and run `bundle install`.
10
+
11
+ ```ruby
12
+ gem 'presigned_upload'
13
+ ```
14
+
15
+ Or install it yourself as:
16
+ ```sh
17
+ gem install presigned_upload
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ TODO: Write usage instructions here
23
+
24
+ ## Contributing
25
+
26
+ Bug reports and pull requests are welcome on GitHub at https://github.com/DenisStael/presigned_upload.
27
+
28
+ ## License
29
+
30
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,12 @@
1
+ class Create<%= model_name.camelize.pluralize %> < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :<%= model_name.underscore.pluralize + migration_id_column %> do |t|
4
+ t.string :original_name, null: false
5
+ t.string :content_type, null: false
6
+ t.string :store_path, null: false
7
+ t.string :upload_status, null: false
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ class <%= model_name.camelize %> < ApplicationRecord
2
+ presigned_uploadable_model
3
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module PresignedUpload
7
+ class UploadableModelGenerator < Rails::Generators::Base
8
+ include Rails::Generators::Migration
9
+
10
+ source_root File.expand_path("templates", __dir__)
11
+
12
+ argument :model_name, type: :string, desc: "Name of presigned uploadable model"
13
+ class_option :uuid, type: :boolean, default: false, desc: "Use UUID type for primary key"
14
+
15
+ def self.next_migration_number(path)
16
+ ActiveRecord::Generators::Base.next_migration_number(path)
17
+ end
18
+
19
+ def create_model_and_migration
20
+ generate_model
21
+ generate_migration
22
+ end
23
+
24
+ private
25
+
26
+ def generate_model
27
+ template "uploadable_model.rb", File.join("app", "models", "#{model_name.underscore}.rb")
28
+ end
29
+
30
+ def migration_id_column
31
+ options.uuid? ? ", id: :uuid" : ""
32
+ end
33
+
34
+ def generate_migration
35
+ migration_template "migration.rb", "db/migrate/create_#{model_name.underscore.pluralize}.rb"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "presigned_upload/adapter/base"
4
+
5
+ module PresignedUpload
6
+ module Adapter
7
+ #
8
+ # The `Aws` class is an adapter for interacting with the Amazon Simple Storage Service (S3) using the AWS SDK.
9
+ # It inherits from `Adapter::Base` and implements methods for generating presigned URLs, uploading files,
10
+ # and deleting files.
11
+ #
12
+ # @see Adapter::Base
13
+ class Aws < Base
14
+ #
15
+ # Generates a presigned URL for the specified key, HTTP method, and expiration time.
16
+ #
17
+ # @param [String] key The key or identifier of the file in the storage.
18
+ # @param [Symbol] method The HTTP method for which the presigned URL is generated (e.g., :put, :get).
19
+ # @param [Integer] expires_in The duration in seconds for which the URL is valid.
20
+ #
21
+ # @return [String] The presigned URL for the specified key, method, and expiration time.
22
+ def presigned_url(key, method, expires_in)
23
+ bucket.object(key).presigned_url(method, expires_in: expires_in)
24
+ end
25
+
26
+ # Uploads the specified file to the storage with the given key.
27
+ #
28
+ # @param [String] file The path to the local file to be uploaded.
29
+ # @param [String] key The key or identifier for the file in the storage.
30
+ #
31
+ # @return [void]
32
+ def upload_file(file, key)
33
+ object = bucket.object(key)
34
+ object.upload_file(file)
35
+ end
36
+
37
+ # Deletes the file with the specified key from the storage.
38
+ #
39
+ # @param [String] key The key or identifier of the file to be deleted.
40
+ #
41
+ # @return [void]
42
+ def delete_file(key)
43
+ bucket.object(key).delete
44
+ end
45
+
46
+ private
47
+
48
+ # Returns the AWS S3 client for interacting with the service.
49
+ #
50
+ # @return [Aws::S3::Client] The AWS S3 client.
51
+ def client
52
+ @client ||= ::Aws::S3::Client.new
53
+ end
54
+
55
+ # Returns the AWS S3 resource for interacting with S3 objects and buckets.
56
+ #
57
+ # @return [Aws::S3::Resource] The AWS S3 resource.
58
+ def resource
59
+ @resource ||= ::Aws::S3::Resource.new
60
+ end
61
+
62
+ # Returns the name of the S3 bucket configured for storage.
63
+ #
64
+ # @return [String] The name of the S3 bucket.
65
+ def bucket_name
66
+ @bucket_name ||= storage_options[:bucket]
67
+ end
68
+
69
+ # Returns the S3 bucket resource for the configured bucket name.
70
+ #
71
+ # @return [Aws::S3::Bucket] The S3 bucket resource.
72
+ def bucket
73
+ @bucket ||= resource.bucket(bucket_name)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PresignedUpload
4
+ #
5
+ # The `Adapter` module contains classes responsible for interfacing with different storage services.
6
+ # Each adapter class should inherit from `PresignedUpload::Adapter::Base`.
7
+ #
8
+ # @see PresignedUpload::Adapter::Base
9
+ module Adapter
10
+ # The `Base` class serves as the base class for all storage adapters in the `PresignedUpload` module.
11
+ # It provides a common interface for accessing storage configurations.
12
+ #
13
+ # @see PresignedUpload::Adapter
14
+ class Base
15
+ #
16
+ # Initializes a new instance of the adapter.
17
+ #
18
+ def initialize
19
+ @storage_options = PresignedUpload.configuration.storage_options
20
+ end
21
+
22
+ protected
23
+
24
+ # Returns the storage configuration for the adapter.
25
+ #
26
+ # @return [Hash] The storage configuration.
27
+ attr_reader :storage_options
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PresignedUpload
4
+ #
5
+ # Configuration class
6
+ #
7
+ class Configuration
8
+ AVAILABLE_STORAGES = [:aws].freeze
9
+
10
+ attr_accessor :storage, :storage_options
11
+ attr_reader :adapter_class
12
+
13
+ def initialize
14
+ @storage = nil
15
+ @storage_options = {}
16
+ end
17
+
18
+ def configure!
19
+ unless AVAILABLE_STORAGES.include?(storage)
20
+ raise InvalidStorage, "Invalid storage. Allowed types are: #{AVAILABLE_STORAGES}"
21
+ end
22
+
23
+ raise InvalidStorageConfig, "Empty storage configuration" if storage_options.empty?
24
+
25
+ case storage
26
+ when :aws
27
+ load_aws
28
+ end
29
+
30
+ self
31
+ end
32
+
33
+ private
34
+
35
+ def load_aws
36
+ require_aws_dependencies!
37
+
38
+ required_config_keys = [:bucket]
39
+ storage_options.each_key { |key| storage_options.except!(key) unless required_config_keys.include?(key) }
40
+
41
+ unless required_config_keys.all? { |key| storage_options.key?(key) }
42
+ raise InvalidStorageConfig, "Missing storage configuration. Required keys are: #{required_config_keys}"
43
+ end
44
+
45
+ @adapter_class = PresignedUpload::Adapter::Aws
46
+ end
47
+
48
+ def require_aws_dependencies!
49
+ unless defined?(::Aws::S3)
50
+ raise MissingDependency, "Missing required dependency\n
51
+ PresignedUpload requires 'aws-sdk-s3' gem to work properly with Aws S3 storage.\n
52
+ To fix this error, consider adding [gem 'aws-sdk-s3'] into your Gemfile."
53
+ end
54
+
55
+ require "presigned_upload/adapter/aws"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PresignedUpload
4
+ class InvalidStorage < StandardError; end
5
+ class InvalidStorageConfig < StandardError; end
6
+ class MissingDependency < StandardError; end
7
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "presigned_upload/uploadable"
4
+
5
+ module PresignedUpload
6
+ #
7
+ # Module extended by ActiveRecord::Base to allow configuring models with resources of the gem
8
+ #
9
+ module Models
10
+ #
11
+ # Calling this method in the context of the model class includes Uploadable module, which makes
12
+ # available the methods for requesting presigned_urls and deleting file from the cloud storage
13
+ #
14
+ # @example:
15
+ #
16
+ # UploadLink < ApplicationRecord
17
+ # presigned_uploadable
18
+ # end
19
+ #
20
+ # upload_link = UploadLink.new
21
+ # upload_link.presigned_url('key', :get, expires_in = 3600)
22
+ # upload_link.delete_file('key')
23
+ #
24
+ def presigned_uploadable
25
+ include Uploadable
26
+ end
27
+
28
+ # rubocop:disable Metrics/MethodLength
29
+ #
30
+ # Calling this method in the context of the model class includes Uploadable::Model module, which includes
31
+ # all the behavior from the Uploadable module and the Uploadable::Model, including validations and callbacks
32
+ #
33
+ # @param [Hash] options Options hash
34
+ # @option options [Symbol] :store_path The path to the storage location
35
+ # Accepts a Symbol value, which will try to call a method with same name
36
+ # in model, a String value representing the store path or a Proc to call
37
+ #
38
+ # @example
39
+ #
40
+ # UploadLink < ApplicationRecord
41
+ # presigned_uploadable_model, store_path: :generate_store_path
42
+ # end
43
+ #
44
+ def presigned_uploadable_model(options = {})
45
+ include Uploadable::Model
46
+
47
+ store_path = options[:store_path]
48
+
49
+ before_create do
50
+ self.store_path =
51
+ case store_path
52
+ when Symbol
53
+ __send__(store_path)
54
+ when String
55
+ store_path
56
+ when Proc
57
+ store_path.call
58
+ else
59
+ "uploads/#{model_name.plural}/#{original_name}"
60
+ end
61
+ end
62
+ end
63
+ # rubocop:enable Metrics/MethodLength
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+ require "presigned_upload/models"
5
+
6
+ # rubocop:disable Style/Documentation
7
+
8
+ module PresignedUpload
9
+ class Railtie < Rails::Railtie
10
+ initializer "presigned_upload.initialize" do
11
+ ActiveSupport.on_load(:active_record) do
12
+ ActiveRecord::Base.extend PresignedUpload::Models
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ # rubocop:enable Style/Documentation
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PresignedUpload
4
+ # Storage module that provides a common interface for interacting with different storage adapters.
5
+ #
6
+ # @example
7
+ # class MyUploader
8
+ # include Storage
9
+ # end
10
+ #
11
+ # uploader = MyUploader.new
12
+ # url = uploader.presigned_url('key', :put, 3600)
13
+ # uploader.delete_file('key')
14
+ #
15
+ module Storage
16
+ # Generates a presigned URL for the specified key, HTTP method, and expiration time.
17
+ #
18
+ # @param [String] key The key or identifier of the file in the storage.
19
+ # @param [Symbol] method The HTTP method for which the presigned URL is generated (e.g., :put, :get).
20
+ # @param [Integer] expires_in The duration in seconds for which the URL is valid (default is 3600 seconds).
21
+ #
22
+ # @return [String] The presigned URL for the specified key and method.
23
+ def presigned_url(key, method, expires_in = 3600)
24
+ adapter.presigned_url(key, method, expires_in)
25
+ end
26
+
27
+ # Deletes the file with the specified key from the storage.
28
+ #
29
+ # @param [String] key The key or identifier of the file to be deleted.
30
+ #
31
+ def delete_file(key)
32
+ adapter.delete_file(key)
33
+ end
34
+
35
+ private
36
+
37
+ # Returns the storage adapter based on the configured storage type.
38
+ #
39
+ # @return [PresignedUpload::Adapter::Base] An instance of the configured storage adapter.
40
+ def adapter
41
+ @adapter ||= PresignedUpload.adapter_class.new
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "presigned_upload/storage"
4
+ require "active_support/concern"
5
+
6
+ module PresignedUpload
7
+ #
8
+ # The `Uploadable` module integrates storage functionality with a model, allowing handling
9
+ # file uploads and associated storage operations. It includes the capabilities provided by the
10
+ # `PresignedUpload::Storage` module.
11
+ #
12
+ # This module is designed to be included in ActiveRecord models to facilitate common file upload
13
+ # operations, such as generating presigned URLs, deleting stored files, and managing upload status.
14
+ #
15
+ # @example
16
+ #
17
+ # class MyUploadableModel < ApplicationRecord
18
+ # include Uploadable::Model
19
+ # end
20
+ #
21
+ # model = MyUploadableModel.new(original_name: 'example.txt', content_type: 'text/plain', upload_status: :initial)
22
+ # model.upload_url # Generates a presigned URL for file upload.
23
+ # model.url # Retrieves a presigned URL for accessing the stored file.
24
+ #
25
+ # @see PresignedUpload::Storage
26
+ module Uploadable
27
+ include PresignedUpload::Storage
28
+
29
+ # The `Model` submodule extends ActiveSupport::Concern to provide upload-related functionality
30
+ # to ActiveRecord models.
31
+ module Model
32
+ extend ActiveSupport::Concern
33
+
34
+ include Uploadable
35
+
36
+ included do
37
+ attr_readonly :original_name, :content_type, :store_path
38
+
39
+ validates :original_name, :content_type, :upload_status, presence: true
40
+
41
+ enum upload_status: { initial: "initial", completed: "completed" }
42
+
43
+ after_destroy { delete_stored_file }
44
+ end
45
+
46
+ # Returns a presigned URL for accessing the stored file. Returns `nil` if the upload status is not 'completed'.
47
+ #
48
+ # @return [String, nil] The presigned URL for accessing the stored file or `nil` if the
49
+ # upload status is not completed.
50
+ #
51
+ def url
52
+ return unless completed?
53
+
54
+ presigned_url(store_path, :get)
55
+ end
56
+
57
+ # Returns a presigned URL for uploading the file. Returns `nil` if the store path is blank or the
58
+ # upload status is 'completed'.
59
+ #
60
+ # @return [String, nil] The presigned URL for uploading the file or `nil` if the upload status is
61
+ # 'completed' or store path is not present.
62
+ #
63
+ def upload_url
64
+ return if store_path.blank? || completed?
65
+
66
+ presigned_url(store_path, :put)
67
+ end
68
+
69
+ # Deletes the stored file associated with the model.
70
+ #
71
+ def delete_stored_file
72
+ delete_file(store_path)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PresignedUpload
4
+ VERSION = "0.1.1"
5
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "presigned_upload/railtie"
4
+ require "presigned_upload/version"
5
+ require "presigned_upload/configuration"
6
+ require "presigned_upload/errors"
7
+ require "presigned_upload/adapter/base"
8
+
9
+ # The `PresignedUpload` module serves as the main module for the presigned file upload functionality.
10
+ # It provides configuration options, such as storage type and configuration settings.
11
+ #
12
+ module PresignedUpload
13
+ class << self
14
+ attr_accessor :configuration
15
+
16
+ def configure
17
+ self.configuration ||= Configuration.new
18
+
19
+ yield(configuration)
20
+
21
+ configuration.configure!
22
+ end
23
+ end
24
+
25
+ def self.adapter_class
26
+ @adapter_class ||= configuration.adapter_class
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: presigned_upload
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Denis Stael
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.21'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.21'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.4.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.2
55
+ description: ' "This gem provides an easy way to handle direct file uploads to
56
+ cloud storage services via presigned URL."
57
+
58
+ '
59
+ email:
60
+ - denissantistael@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".rspec"
66
+ - ".rubocop.yml"
67
+ - CHANGELOG.md
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - lib/generators/presigned_upload/templates/migration.rb
73
+ - lib/generators/presigned_upload/templates/uploadable_model.rb
74
+ - lib/generators/presigned_upload/uploadable_model_generator.rb
75
+ - lib/presigned_upload.rb
76
+ - lib/presigned_upload/adapter/aws.rb
77
+ - lib/presigned_upload/adapter/base.rb
78
+ - lib/presigned_upload/configuration.rb
79
+ - lib/presigned_upload/errors.rb
80
+ - lib/presigned_upload/models.rb
81
+ - lib/presigned_upload/railtie.rb
82
+ - lib/presigned_upload/storage.rb
83
+ - lib/presigned_upload/uploadable.rb
84
+ - lib/presigned_upload/version.rb
85
+ homepage: https://github.com/DenisStael/presigned_upload
86
+ licenses:
87
+ - MIT
88
+ metadata:
89
+ homepage_uri: https://github.com/DenisStael/presigned_upload
90
+ source_code_uri: https://github.com/DenisStael/presigned_upload
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 2.6.0
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubygems_version: 3.3.7
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Control model associated files uploads via presigned URL to cloud storage
110
+ services.
111
+ test_files: []