activestorage-delayed 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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