presigned_upload 0.1.1 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 651464bf9650c6acb0cbd6da5f0d3e1cb41bcf16c2825e32a64fd102e214917b
4
- data.tar.gz: e07b382fd743b259a3196912dbb19eff4069e55381e20eb7b9a20f622b20aa88
3
+ metadata.gz: ca293e74541ff82d393ac583e295699df5f5fbf80d32c2b4f4365fc820e76959
4
+ data.tar.gz: 75e337709fe872cf5f5fc71470017f37e5b6dc5266152ae166cec6d29fcc58bc
5
5
  SHA512:
6
- metadata.gz: 8b7f57130a706d1d5651652134b152cf51a4dcd6442382c8c608d22d2b3af1380048f6bca891a811559cc94f7bc892a017170962ea23f92f6d2149ccf98ea066
7
- data.tar.gz: 9329538342ea4ae88cd2b571e92c6cc87512a2f8f455cf6332267768ebdc9d170da6daed49bad15ad276cf77d801d3210076b82fdb07c1bbaae1dae17598fded
6
+ metadata.gz: ee83ec4b1fd4a499330eeb44eeaf0d75c5ac2f413109ef3fe41e4f555d3c1616d23fe4c819eeb761fa399e757177c71cf382045a0d1db058ac49422d1a8456a4
7
+ data.tar.gz: 4d57cc6b0317400c8637e2cfc71bed2a3bc3bfdfb04be6ab82d0a33fd0963f6ea68799697498543e651f958864e7299f7e1d0b1c8c0e650303d95a541c11c32a
data/.rubocop.yml CHANGED
@@ -26,3 +26,8 @@ Metrics/BlockLength:
26
26
  Enabled: true
27
27
  Exclude:
28
28
  - "spec/**/*"
29
+
30
+ Naming/HeredocDelimiterNaming:
31
+ Enabled: true
32
+ Exclude:
33
+ - "presigned_upload.gemspec"
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --exclude lib/generators/presigned_upload/templates/
data/CHANGELOG.md CHANGED
@@ -3,3 +3,11 @@
3
3
  ## [0.1.0] - 2023-11-23
4
4
 
5
5
  - Initial release
6
+
7
+ ## [0.2.0] - 2024-07-25
8
+
9
+ - Removed `store_path` attribute from migration
10
+ - Moved `store_path` from `before_create` callback to `store_dir` instance method
11
+ - The `store_path` now is mounted when it is called, joining `store_dir` + `original_name`
12
+ - Added README documentation and installation instructions
13
+ - Added `install_generator.rb` to generate the PresignedUpload default initializer
data/README.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # PresignedUpload
2
2
 
3
- Gem designed to control file uploads via presigned URLs to cloud storage services.
3
+ Control file uploads via presigned URLs to cloud storage services.
4
4
 
5
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
6
 
7
7
  ## Installation
8
8
 
9
+ ### 1. Add the gem into your project
10
+
9
11
  Add this to your Gemfile and run `bundle install`.
10
12
 
11
13
  ```ruby
@@ -17,13 +19,168 @@ Or install it yourself as:
17
19
  gem install presigned_upload
18
20
  ```
19
21
 
22
+ ### 2. Create the initializer file
23
+
24
+ Run the generator to create the initializer file:
25
+ ```sh
26
+ rails g presigned_upload:install
27
+ ```
28
+
29
+ ### 3. Generate Uploadable Model
30
+
31
+ Use the PresignedUpload generator to create your uploadable model.
32
+
33
+ This model is intended to be a representation of access to a file, and also its basic informations.
34
+
35
+ For example, if you want create a UploadLink model, you can use:
36
+ ```sh
37
+ rails g presigned_upload:uploadable_model UploadLink
38
+ ```
39
+ If your database uses UUID for the primary and foreign keys, you can pass the `--uuid` option:
40
+ ```sh
41
+ rails g presigned_upload:uploadable_model UploadLink --uuid
42
+ ```
43
+
44
+ The generator will create the model with the given name and the migration file:
45
+ ```ruby
46
+ # app/models/upload_link.rb
47
+ class UploadLink < ApplicationRecord
48
+ presigned_uploadable_model
49
+ end
50
+
51
+ # This columns are required, but you can add more if you need.
52
+ # For example, you can create a column called 'storage_size'
53
+ # to save the storage size of the file
54
+ class CreateUploadLinks < ActiveRecord::Migration[7.0]
55
+ def change
56
+ create_table :upload_links, id: :uuid do |t|
57
+ t.string :original_name, null: false
58
+ t.string :content_type, null: false
59
+ t.string :upload_status, null: false
60
+
61
+ t.timestamps
62
+ end
63
+ end
64
+ end
65
+ ```
66
+ By default, an uploadable model contains:
67
+ - `original_name`: The original name of the file
68
+ - `content_type`: The content-type of the file _(Utile for validations)_
69
+ - `upload_status`: The status of the upload process [`initial`, `completed`]
70
+
71
+ ### 4. Run the migration
72
+
73
+ ```
74
+ rails db:migrate
75
+ ```
76
+
20
77
  ## Usage
21
78
 
22
- TODO: Write usage instructions here
79
+ ### Configuring initializer
80
+
81
+ You can configure the presigned_upload initializer to set the storage service and its options.
82
+
83
+ For AWS S3 for example, you going to need to add the `storage` to `:aws` and inform the `bucket` where you want to create presigned URLs in order to upload and access files:
84
+ ```ruby
85
+ PresignedUpload.configure do |config|
86
+ config.storage = :aws
87
+ config.storage_options = {
88
+ bucket: 'my_bucket'
89
+ }
90
+ end
91
+ ```
92
+
93
+ **Important:** For an AWS configuration, you need to add the [AWS SDK for Ruby](https://github.com/aws/aws-sdk-ruby) in order to `PresignedUpload` gem to work correctly:
94
+ ```ruby
95
+ gem 'aws-sdk-s3'
96
+ ```
97
+ If you don't add this, an error will be raised when trying to run Rails.
98
+
99
+ ### Uploadable Model
100
+
101
+ The uploadable model will be used to access files in the cloud storage services. Below there are some of the methods that can be accessed:
102
+ ```ruby
103
+ # Returns a presigned URL for uploading the file
104
+ # Only returns the URL if the upload_status is 'initial'
105
+ upload_link.upload_url
106
+
107
+ # Returns a presigned URL for accessing the stored file
108
+ # Only returns the URL if the upload_status is 'completed'
109
+ upload_link.url
110
+
111
+ # Deletes the stored file from the cloud
112
+ # This method is automatically called in before_destroy
113
+ # callback when you destroy the record
114
+ upload_link.delete_stored_file
115
+ ```
116
+
117
+ In order to be able to use this methods, you need to configure the store directory where the file will be stored.
118
+
119
+ #### Storage path
120
+
121
+ By default, PresignedUpload inserts the method `presigned_uploadable_model` in your Model, that sets the value of the `store_dir` to: `"uploads/#{model_name.plural}/#{id}"`.
122
+
123
+ The final `store_path` of the file in the cloud will be the junction between `store_dir` + `original_name`.
124
+
125
+ So, in the example below, the file will be stored as `uploads/upload_links/123/my_file.txt`:
126
+ ```ruby
127
+ class UploadLink < ApplicationRecord
128
+ presigned_uploadable_model
129
+ end
130
+
131
+ upload_link.id = '123'
132
+ upload_link.original_name = 'my_file.txt'
133
+ upload_link.store_path
134
+ # => uploads/upload_links/123/my_file.txt
135
+ ```
136
+
137
+ #### Changing the storage directory
138
+
139
+ The `presigned_uploadable_model` method accepts the `:store_dir` option, that can be a `Symbol`, a `String` or a `Proc`.
140
+
141
+ Using a string:
142
+ ```ruby
143
+ class UploadLink < ApplicationRecord
144
+ presigned_uploadable_model store_dir: '/uploads/my/custom/path'
145
+ end
146
+
147
+ upload_link.original_name = 'my_file.txt'
148
+ upload_link.store_path
149
+ # => "/uploads/my/custom/path/my_file.txt"
150
+ ```
151
+
152
+ Using a Proc:
153
+ ```ruby
154
+ class UploadLink < ApplicationRecord
155
+ presigned_uploadable_model store_dir: -> { "/uploads/upload_links/#{id}" }
156
+ end
157
+
158
+ upload_link.id = '123'
159
+ upload_link.original_name = 'my_file.txt'
160
+ upload_link.store_path
161
+ # => "/uploads/upload_links/123/my_file.txt"
162
+ ```
163
+
164
+ Using a Symbol:
165
+ ```ruby
166
+ class UploadLink < ApplicationRecord
167
+ presigned_uploadable_model store_dir: :my_custom_dir
168
+
169
+ # Using as a symbol, the code will expect a instance method with same name
170
+ def my_custom_dir
171
+ "/my/custom/dir/#{id}"
172
+ end
173
+ end
174
+
175
+ upload_link.id = '123'
176
+ upload_link.original_name = 'my_file.txt'
177
+ upload_link.store_path
178
+ # => "/my/custom/dir/123/my_file.txt"
179
+ ```
23
180
 
24
181
  ## Contributing
25
182
 
26
- Bug reports and pull requests are welcome on GitHub at https://github.com/DenisStael/presigned_upload.
183
+ Bug reports and pull requests are welcome on GitHub at https://github.com/denisstael/presigned_upload.
27
184
 
28
185
  ## License
29
186
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module PresignedUpload
6
+ class InstallGenerator < Rails::Generators::Base
7
+ source_root File.expand_path("templates", __dir__)
8
+
9
+ def generate_initializer
10
+ template "initializer.rb", "config/initializers/presigned_upload.rb"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Use this initializer to configure PresignedUpload.
4
+ #
5
+ PresignedUpload.configure do |config|
6
+ # Configure the storage option to define which storage service will be used.
7
+ config.storage = :aws
8
+
9
+ # Configure the storage_options for additional information about the choosen storage service.
10
+ config.storage_options = {
11
+ bucket: 'my_bucket'
12
+ }
13
+ end
@@ -3,7 +3,6 @@ class Create<%= model_name.camelize.pluralize %> < ActiveRecord::Migration[7.0]
3
3
  create_table :<%= model_name.underscore.pluralize + migration_id_column %> do |t|
4
4
  t.string :original_name, null: false
5
5
  t.string :content_type, null: false
6
- t.string :store_path, null: false
7
6
  t.string :upload_status, null: false
8
7
 
9
8
  t.timestamps
@@ -17,10 +17,10 @@ module PresignedUpload
17
17
 
18
18
  def configure!
19
19
  unless AVAILABLE_STORAGES.include?(storage)
20
- raise InvalidStorage, "Invalid storage. Allowed types are: #{AVAILABLE_STORAGES}"
20
+ raise InvalidStorage, "Invalid storage option. Allowed types are: #{AVAILABLE_STORAGES}"
21
21
  end
22
22
 
23
- raise InvalidStorageConfig, "Empty storage configuration" if storage_options.empty?
23
+ raise InvalidStorageConfig, "Empty storage options configuration" if storage_options.empty?
24
24
 
25
25
  case storage
26
26
  when :aws
@@ -26,38 +26,37 @@ module PresignedUpload
26
26
  end
27
27
 
28
28
  # rubocop:disable Metrics/MethodLength
29
- #
29
+
30
30
  # Calling this method in the context of the model class includes Uploadable::Model module, which includes
31
31
  # all the behavior from the Uploadable module and the Uploadable::Model, including validations and callbacks
32
32
  #
33
33
  # @param [Hash] options Options hash
34
- # @option options [Symbol] :store_path The path to the storage location
34
+ # @option options [Symbol] :store_dir The path to the storage location directory
35
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
36
+ # in model, a String value representing the store directory or a Proc to call
37
37
  #
38
38
  # @example
39
39
  #
40
40
  # UploadLink < ApplicationRecord
41
- # presigned_uploadable_model, store_path: :generate_store_path
41
+ # presigned_uploadable_model, store_dir: :generate_store_dir
42
42
  # end
43
43
  #
44
44
  def presigned_uploadable_model(options = {})
45
45
  include Uploadable::Model
46
46
 
47
- store_path = options[:store_path]
47
+ store_dir = options[:store_dir]
48
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
49
+ define_method :store_dir do
50
+ case store_dir
51
+ when Symbol
52
+ __send__(store_dir)
53
+ when String
54
+ store_dir
55
+ when Proc
56
+ instance_exec(&store_dir)
57
+ else
58
+ "uploads/#{model_name.plural}/#{id}"
59
+ end
61
60
  end
62
61
  end
63
62
  # rubocop:enable Metrics/MethodLength
@@ -3,10 +3,8 @@
3
3
  require "rails/railtie"
4
4
  require "presigned_upload/models"
5
5
 
6
- # rubocop:disable Style/Documentation
7
-
8
6
  module PresignedUpload
9
- class Railtie < Rails::Railtie
7
+ class Railtie < Rails::Railtie # :nodoc:
10
8
  initializer "presigned_upload.initialize" do
11
9
  ActiveSupport.on_load(:active_record) do
12
10
  ActiveRecord::Base.extend PresignedUpload::Models
@@ -14,5 +12,3 @@ module PresignedUpload
14
12
  end
15
13
  end
16
14
  end
17
-
18
- # rubocop:enable Style/Documentation
@@ -34,8 +34,6 @@ module PresignedUpload
34
34
  include Uploadable
35
35
 
36
36
  included do
37
- attr_readonly :original_name, :content_type, :store_path
38
-
39
37
  validates :original_name, :content_type, :upload_status, presence: true
40
38
 
41
39
  enum upload_status: { initial: "initial", completed: "completed" }
@@ -54,14 +52,13 @@ module PresignedUpload
54
52
  presigned_url(store_path, :get)
55
53
  end
56
54
 
57
- # Returns a presigned URL for uploading the file. Returns `nil` if the store path is blank or the
58
- # upload status is 'completed'.
55
+ # Returns a presigned URL for uploading the file. Returns `nil` if the upload status is 'completed'.
59
56
  #
60
57
  # @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.
58
+ # already marked as completed.
62
59
  #
63
60
  def upload_url
64
- return if store_path.blank? || completed?
61
+ return if completed?
65
62
 
66
63
  presigned_url(store_path, :put)
67
64
  end
@@ -71,6 +68,18 @@ module PresignedUpload
71
68
  def delete_stored_file
72
69
  delete_file(store_path)
73
70
  end
71
+
72
+ # Returns the file store path.
73
+ #
74
+ # The store path is constructed by combining the storage directory
75
+ # with the `original_name` of the file. If `store_dir` is present, it is
76
+ # included in the path. If `store_dir` is not present, then the file
77
+ # will be saved in the root directory.
78
+ #
79
+ # @return [String] the storage path for the uploaded file.
80
+ def store_path
81
+ "#{store_dir.present? ? "#{store_dir}/" : ""}#{original_name}"
82
+ end
74
83
  end
75
84
  end
76
85
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PresignedUpload
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: presigned_upload
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Stael
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-28 00:00:00.000000000 Z
11
+ date: 2024-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -52,8 +52,8 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
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."
55
+ description: ' "Handle direct file uploads to cloud storage services via presigned
56
+ URLs."
57
57
 
58
58
  '
59
59
  email:
@@ -64,11 +64,14 @@ extra_rdoc_files: []
64
64
  files:
65
65
  - ".rspec"
66
66
  - ".rubocop.yml"
67
+ - ".yardopts"
67
68
  - CHANGELOG.md
68
69
  - Gemfile
69
70
  - LICENSE.txt
70
71
  - README.md
71
72
  - Rakefile
73
+ - lib/generators/presigned_upload/install_generator.rb
74
+ - lib/generators/presigned_upload/templates/initializer.rb
72
75
  - lib/generators/presigned_upload/templates/migration.rb
73
76
  - lib/generators/presigned_upload/templates/uploadable_model.rb
74
77
  - lib/generators/presigned_upload/uploadable_model_generator.rb
@@ -82,12 +85,13 @@ files:
82
85
  - lib/presigned_upload/storage.rb
83
86
  - lib/presigned_upload/uploadable.rb
84
87
  - lib/presigned_upload/version.rb
85
- homepage: https://github.com/DenisStael/presigned_upload
88
+ homepage: https://github.com/denisstael/presigned_upload
86
89
  licenses:
87
90
  - MIT
88
91
  metadata:
89
- homepage_uri: https://github.com/DenisStael/presigned_upload
90
- source_code_uri: https://github.com/DenisStael/presigned_upload
92
+ homepage_uri: https://github.com/denisstael/presigned_upload
93
+ source_code_uri: https://github.com/denisstael/presigned_upload
94
+ documentation_uri: https://rubydoc.info/gems/presigned_upload/0.2.0
91
95
  post_install_message:
92
96
  rdoc_options: []
93
97
  require_paths:
@@ -106,6 +110,6 @@ requirements: []
106
110
  rubygems_version: 3.3.7
107
111
  signing_key:
108
112
  specification_version: 4
109
- summary: Control model associated files uploads via presigned URL to cloud storage
113
+ summary: Control model associated files uploads via presigned URLs to cloud storage
110
114
  services.
111
115
  test_files: []