activestorage-delayed 0.1.3 → 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: 21cd7652c2fbe15057bf6f36a36c7ec510ed1e622f5adb0e0f566f5a2e30c111
4
- data.tar.gz: e16a8f72a0cc7049dfccb958499ba112659abcf0afbf03e9961fdcaea6cd76cd
3
+ metadata.gz: 23b95115e89560a1c7e3a880f0b89a1d7aaf99fe4b6e54c1b207ce0d435dfda2
4
+ data.tar.gz: 727dd8e29453607c884e4ddf126fd1f41da790bb8c1db89ae30cedc506b02900
5
5
  SHA512:
6
- metadata.gz: 1c69f49fc4c77684d71a9ccc9b6fdf09bdea824a0f6588974024dce997ebfe7bac49bfa0c257a8c4610437a133837d00a3040e812b8d1014f9efb5c078104079
7
- data.tar.gz: '0802bc892fa31b38e35042860919944b7eeee09811057eb082d0a4eaf426d880a624aa306835e75acbf54cc9cf0e631c3ab5a07e18307a0f9c70ef9b99492160'
6
+ metadata.gz: 976b9b1c03bab65f651fb81d2915aeb9561e380fbd35b26069c3263d4f443f029cc4fd22bee015a4e946eb20487b68228a5d66d175978c556f0a76e6979b59b8
7
+ data.tar.gz: 29d8ae5308daa56f5845e4deeb70a709cce48a9f5c48b2759ad4473cea0041c6a84a0f50b50657235177d5d10dd6736696c305a304d38474dc2cca05d5a6de5b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activestorage-delayed (0.1.3)
4
+ activestorage-delayed (0.2.0)
5
5
  activestorage
6
6
  rails
7
7
 
data/README.md CHANGED
@@ -39,7 +39,7 @@ Note: This gem assumes that the app has already configured activestorage.
39
39
  class User < ApplicationRecord
40
40
  include ActivestorageDelayed::DelayedConcern
41
41
 
42
- has_one_attached :photo, require: true, use_filename: true
42
+ has_one_attached :photo, required: true, use_filename: true, variant_info: { resize_to_fit: [400, 400], convert: 'jpg' }
43
43
  delayed_attach :photo
44
44
 
45
45
  has_many_attached :certificates
@@ -48,8 +48,9 @@ end
48
48
 
49
49
  ```
50
50
  ### `delayed_attach` accepts an optional hash with the following options:
51
- - `require`: If set to `true`, the `photo` or the `photo_tmp` will be required before saving.
51
+ - `required`: If set to `true`, the `photo` or the `photo_tmp` will be required before saving.
52
52
  - `use_filename`: If set to `true`, the image filename will be used as the name of uploaded file instead of the hash-key used by `activestorage`
53
+ - `variant_info`: (Hash) Variant information to be performed before uploading the file.
53
54
 
54
55
  ### Examples to upload files in background
55
56
  - Upload a single file
@@ -90,7 +91,7 @@ end
90
91
  User.first.update(certificates_tmp: { clean_before: true, files: [File.open('my_file.png')] })
91
92
  ```
92
93
 
93
- - Upload files with custom names (requires `use_filename: true`)
94
+ - Upload files with custom names (requires `use_filename: true`): `<attr_name>_filename`
94
95
  ```ruby
95
96
  class User < ApplicationRecord
96
97
  def photo_filename(filename)
@@ -101,42 +102,27 @@ end
101
102
  When `<attr_name>_filename` is defined, then it is called to fetch the uploaded file name.
102
103
  Note: Check [this](https://gist.github.com/owen2345/33730a452d73b6b292326bb602b0ee6b) if you want to rename an already uploaded file (remote file)
103
104
 
104
- - Capture event when file upload has failed
105
+ - Capture event when file upload has failed: `<attr_name>_error_upload`
105
106
  ```ruby
106
107
  class User < ApplicationRecord
107
- def ast_delayed_on_error(attr_name, error)
108
- puts "Failed #{attr_name} with #{error}"
108
+ def photo_error_upload(error)
109
+ puts "Failed with #{error}"
109
110
  end
110
111
  end
111
112
  ```
112
113
 
113
- - Capture event when file has been uploaded
114
+ - Capture event when file has been uploaded: `<attr_name>_after_upload`
114
115
  ```ruby
115
116
  class User < ApplicationRecord
116
- after_save_commit do
117
- puts 'Photo has been uploaded' if photo.blob.present?
118
- puts 'No pending enqueued photo uploads' unless photo_delayed_uploads.any?
119
- end
120
-
121
- before_save do
122
- puts "current assigned tmp photo: #{photo_tmp.inspect}"
117
+ def photo_after_upload
118
+ puts "Photo has been uploaded"
123
119
  end
124
120
  end
125
121
  ```
122
+
123
+ Note:
126
124
  `<attr_name>_delayed_uploads` is a `has_many` association that contains the list of scheduled uploads for the corresponding attribute.
127
125
 
128
-
129
- ## Preprocessing original files before uploading (Rails 7+)
130
- ```ruby
131
- class User < ApplicationRecord
132
- has_one_attached :photo do |attachable|
133
- attachable.variant :default, strip: true, quality: 70, resize_to_fill: [200, 200]
134
- end
135
- end
136
- ```
137
- `:default` variant will be used to pre-preprocess the original file before uploading (if defined). By this way you have your desired image size and quality as the original image.
138
-
139
-
140
126
 
141
127
  ## Contributing
142
128
  Bug reports and pull requests are welcome on https://github.com/owen2345/activestorage-delayed. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
@@ -3,10 +3,14 @@
3
3
  module ActivestorageDelayed
4
4
  module DelayedConcern
5
5
  extend ActiveSupport::Concern
6
- included do
6
+ included do # rubocop:disable Metrics/BlockLength
7
7
  @ast_delayed_settings = {}
8
- def self.delayed_attach(attr_name, required: false, use_filename: false) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
9
- @ast_delayed_settings[attr_name] = { use_filename: use_filename }
8
+
9
+ # @param settings (Hash)
10
+ # use_filename: (Boolean)
11
+ # variant_info: (Hash) Sample: { resize_to_fit: [400, 400], convert: 'jpg' }
12
+ def self.delayed_attach(attr_name, required: false, **settings) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
13
+ @ast_delayed_settings[attr_name] = settings
10
14
  tmp_attr_name = :"#{attr_name}_tmp"
11
15
  has_many_attr = :"#{attr_name}_delayed_uploads"
12
16
  attr_accessor tmp_attr_name
@@ -27,11 +31,22 @@ module ActivestorageDelayed
27
31
  delayed_data[:attr_name] = attr_name
28
32
  send(has_many_attr) << send(has_many_attr).new(delayed_data)
29
33
  end
34
+
35
+ # @param filename (String) File name
36
+ define_method "#{attr_name}_filename" do |filename|
37
+ name = File.basename(filename, '.*').parameterize
38
+ is_multiple = send(attr_name).class.name.include?('Many')
39
+ name = "#{SecureRandom.uuid}-#{name}" if is_multiple
40
+ "#{send(:id)}-#{name}#{File.extname(filename)}"
41
+ end
42
+
43
+ define_method "#{attr_name}_after_upload" do
44
+ end
45
+
46
+ # @param _error (Exception)
47
+ define_method "#{attr_name}_error_upload" do |_error|
48
+ end
30
49
  end
31
50
  end
32
-
33
- # @param _attr_name (String)
34
- # @param _error (Exception)
35
- def ast_delayed_on_error(_attr_name, _error); end
36
51
  end
37
52
  end
@@ -18,19 +18,27 @@ module ActivestorageDelayed
18
18
 
19
19
  private
20
20
 
21
- # TODO: check the ability to delete io with save or upload method
22
- # file_data['io'].close
23
- def upload_photos # rubocop:disable Metrics/AbcSize
24
- tmp_files_data.each do |file_data|
25
- model.send(attr_name).attach(file_data.transform_keys(&:to_sym))
26
- end
21
+ def upload_photos
22
+ tmp_files_data.each(&method(:upload_photo))
23
+ model.send("#{attr_name}_after_upload")
27
24
  true
28
25
  rescue => e # rubocop:disable Style/RescueStandardError
29
- Rails.logger.error("********* #{self.class.name} -> Failed uploading files: #{e.message}. #{e.backtrace[0..20]}")
30
- model.ast_delayed_on_error(attr_name, e)
26
+ print_failure(e)
31
27
  false
32
28
  end
33
29
 
30
+ def upload_photo(file_data)
31
+ parse_file_io(file_data) do |io|
32
+ file_data['io'] = io
33
+ model.send(attr_name).attach(file_data.transform_keys(&:to_sym))
34
+ end
35
+ end
36
+
37
+ def print_failure(error)
38
+ Rails.logger.error("***#{self.class.name} -> Failed uploading files: #{error.message}. #{error.backtrace[0..20]}")
39
+ model.send("#{attr_name}_error_upload", error)
40
+ end
41
+
34
42
  def save_changes
35
43
  model.save!
36
44
  delayed_upload.destroy!
@@ -41,7 +49,6 @@ module ActivestorageDelayed
41
49
  @tmp_files_data ||= begin
42
50
  files = JSON.parse(delayed_upload.files || '[]')
43
51
  files.each do |file_data|
44
- file_data['io'] = base64_to_file(file_data)
45
52
  if attr_settings[:use_filename]
46
53
  file_data['key'] = filename_for(file_data['filename'])
47
54
  file_data['filename'] = file_data['key']
@@ -50,12 +57,22 @@ module ActivestorageDelayed
50
57
  end
51
58
  end
52
59
 
53
- def base64_to_file(file_data)
54
- tempfile = Tempfile.new(file_data['filename'])
55
- tempfile.binmode
60
+ def parse_file_io(file_data, &block)
61
+ tempfile = Tempfile.new(file_data['filename'], binmode: true)
56
62
  tempfile.write Base64.decode64(file_data['io'])
57
63
  tempfile.rewind
58
- tempfile
64
+ transform_variation(tempfile, attr_settings[:variant_info]) do |io|
65
+ block.call(io)
66
+ tempfile.close
67
+ end
68
+ end
69
+
70
+ # @param io [StringIO, File]
71
+ # @param variant_info [Hash, Nil] ActiveStorage variant info. Sample: { resize_to_fit: [400, 400], convert: 'jpg' }
72
+ def transform_variation(io, variant_info, &block)
73
+ return block.call(io) unless variant_info
74
+
75
+ ActiveStorage::Variation.wrap(variant_info).transform(io, &block)
59
76
  end
60
77
 
61
78
  def model
@@ -64,11 +81,7 @@ module ActivestorageDelayed
64
81
 
65
82
  def filename_for(filename)
66
83
  method_name = "#{attr_name}_filename".to_sym
67
- return model.send(method_name, filename) if model.respond_to?(method_name)
68
-
69
- name = File.basename(filename, '.*').parameterize
70
- name = "#{SecureRandom.uuid}-#{name}" if support_multiple?
71
- "#{model.id}-#{name}#{File.extname(filename)}"
84
+ model.send(method_name, filename)
72
85
  end
73
86
 
74
87
  def remove_files
@@ -10,7 +10,7 @@ module ActivestorageDelayed
10
10
  self.table_name = 'activestorage_delayed_uploads'
11
11
  attr_accessor :tmp_files
12
12
 
13
- belongs_to :uploadable, polymorphic: true
13
+ belongs_to :uploadable, polymorphic: true, touch: true
14
14
 
15
15
  before_save :parse_tmp_files
16
16
  after_create_commit do
@@ -4,9 +4,5 @@ require 'rails'
4
4
  module ActivestorageDelayed
5
5
  class Railtie < ::Rails::Railtie
6
6
  railtie_name :activestorage_delayed
7
-
8
- config.after_initialize do |_app|
9
- require_relative '../../initializers/upload_default_variation'
10
- end
11
7
  end
12
8
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActivestorageDelayed
4
- VERSION = '0.1.3'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activestorage-delayed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Owen Peredo Diaz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-27 00:00:00.000000000 Z
11
+ date: 2022-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activestorage
@@ -64,7 +64,6 @@ files:
64
64
  - bin/test
65
65
  - db/test.sqlite3
66
66
  - docker-compose.yaml
67
- - initializers/upload_default_variation.rb
68
67
  - lib/activestorage-delayed.rb
69
68
  - lib/activestorage-delayed/delayed_concern.rb
70
69
  - lib/activestorage-delayed/delayed_uploader.rb
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Ability to auto apply :default variant before uploading original image
4
- module ActivetoragePreprocessDefaultVariation
5
- def self.prepended(base)
6
- base.extend(ClassMethods)
7
- end
8
-
9
- def upload_without_unfurling(io) # rubocop:disable Metrics/MethodLength
10
- variant = attachments.first.try(:send, :variants)
11
- default_variant = variant ? variant[:default] : nil
12
- if default_variant && self.class.enabled_default_variant?
13
- ActiveStorage::Variation.wrap(default_variant).transform(io) do |output|
14
- unfurl output, identify: identify
15
- save! if id.present? # update new unfurl information
16
- super(output)
17
- end
18
- else
19
- super(io)
20
- end
21
- end
22
-
23
- module ClassMethods
24
- # To improve testing performance, we don't want to preprocess images in test environment
25
- def enabled_default_variant?
26
- !Rails.env.test?
27
- end
28
- end
29
- end
30
-
31
- ActiveStorage::Blob.prepend ActivetoragePreprocessDefaultVariation