activestorage-delayed 0.1.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 +7 -0
 - data/README.md +140 -0
 - data/Rakefile +5 -0
 - data/lib/activestorage-delayed/delayed_concern.rb +37 -0
 - data/lib/activestorage-delayed/delayed_uploader.rb +93 -0
 - data/lib/activestorage-delayed/delayed_uploader_job.rb +11 -0
 - data/lib/activestorage-delayed/models/delayed_upload.rb +32 -0
 - data/lib/activestorage-delayed/railtie.rb +12 -0
 - data/lib/activestorage-delayed/version.rb +5 -0
 - data/lib/activestorage_delayed.rb +13 -0
 - metadata +82 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: d45bf7babcb289d33cb76078e9e944be721fd42ebd7b28f4bd1ca60fee81c148
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 933186d50d21a26346941e7253f5fdc2b15c194b049411054a2f10d825d52bf2
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 766911783743811c91ac4b7aeb7161783d17128a3ad626321d8220b53862e2182ec5b278fb7f1c3827a2dc3ec9acf30eddc58a05dc1d32280edfd03404b8b82a
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: aa629632c162e3f9b4910242ab89422ee95aca3c6ddc67b190b215b966028eadb1876e4ea9d7463e88fbf94a433683532b6c96d7d8f4ec98cbb8bfb7ae5ffbd6
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,140 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Activestorage Delayed
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ActiveStorage for Rails 6 and 7 does not support to upload files in background which in most cases delays the submit process and then making the visitor get bored or receive a timeout error.    
         
     | 
| 
      
 4 
     | 
    
         
            +
            This is a Ruby on Rails gem to upload activestorage files in background by saving them as base64 encoded in the database and be processed later.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Add this line to your application's Gemfile:
         
     | 
| 
      
 8 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 9 
     | 
    
         
            +
                gem 'activestorage-delayed'
         
     | 
| 
      
 10 
     | 
    
         
            +
              ```
         
     | 
| 
      
 11 
     | 
    
         
            +
            - And then execute: `bundle install`
         
     | 
| 
      
 12 
     | 
    
         
            +
            - Generate the migration: `rails g migration add_activestorage_delayed`
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Add the following content to the migration file:
         
     | 
| 
      
 14 
     | 
    
         
            +
                ```ruby
         
     | 
| 
      
 15 
     | 
    
         
            +
                  create_table :activestorage_delayed_uploads do |t|
         
     | 
| 
      
 16 
     | 
    
         
            +
                    t.references :uploadable, polymorphic: true, null: false
         
     | 
| 
      
 17 
     | 
    
         
            +
                    t.string :attr_name, null: false
         
     | 
| 
      
 18 
     | 
    
         
            +
                    t.string :deleted_ids, default: ''
         
     | 
| 
      
 19 
     | 
    
         
            +
                    t.boolean :clean_before, default: false
         
     | 
| 
      
 20 
     | 
    
         
            +
                    t.text :files
         
     | 
| 
      
 21 
     | 
    
         
            +
                    t.timestamps
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                ```
         
     | 
| 
      
 24 
     | 
    
         
            +
            - Run the migration: `rails db:migrate`
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 28 
     | 
    
         
            +
            - Include `ActivestorageDelayed::DelayedConcern`
         
     | 
| 
      
 29 
     | 
    
         
            +
            - Add `delayed_attach` to the files you want to upload in background
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 32 
     | 
    
         
            +
              class User < ApplicationRecord
         
     | 
| 
      
 33 
     | 
    
         
            +
              include ActivestorageDelayed::DelayedConcern
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              has_one_attached :photo, require: true, use_filename: true
         
     | 
| 
      
 36 
     | 
    
         
            +
              delayed_attach :photo
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              has_many_attached :certificates
         
     | 
| 
      
 39 
     | 
    
         
            +
              delayed_attach :certificates
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            ```
         
     | 
| 
      
 43 
     | 
    
         
            +
            ### `delayed_attach` accepts an optional hash with the following options:
         
     | 
| 
      
 44 
     | 
    
         
            +
            - `require`: If set to `true`, the `photo` or the `photo_tmp` will be required before saving.
         
     | 
| 
      
 45 
     | 
    
         
            +
            - `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`
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            ### Examples to upload files in background 
         
     | 
| 
      
 48 
     | 
    
         
            +
            - Upload a single file
         
     | 
| 
      
 49 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 50 
     | 
    
         
            +
                User.create(photo_tmp: File.open('my_file.png')) # uploads the file in background
         
     | 
| 
      
 51 
     | 
    
         
            +
                User.create(photo: File.open('my_file.png')) # uploads the file directly
         
     | 
| 
      
 52 
     | 
    
         
            +
              ```
         
     | 
| 
      
 53 
     | 
    
         
            +
              **HTML**:
         
     | 
| 
      
 54 
     | 
    
         
            +
              ```haml
         
     | 
| 
      
 55 
     | 
    
         
            +
              f.file_field :photo_tmp
         
     | 
| 
      
 56 
     | 
    
         
            +
              ```
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            - Upload multiple files
         
     | 
| 
      
 59 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 60 
     | 
    
         
            +
                User.create(certificates_tmp: [File.open('my_file.png'), File.open('my_file.png')])
         
     | 
| 
      
 61 
     | 
    
         
            +
              ```    
         
     | 
| 
      
 62 
     | 
    
         
            +
               **HTML**:
         
     | 
| 
      
 63 
     | 
    
         
            +
              ```haml
         
     | 
| 
      
 64 
     | 
    
         
            +
              = f.file_field :certificates_tmp, multiple: true
         
     | 
| 
      
 65 
     | 
    
         
            +
              ```
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            - Deletes first 2 certificates and uploads a new one
         
     | 
| 
      
 68 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 69 
     | 
    
         
            +
                file_ids = User.first.certificates.limit(2).pluck(:id)
         
     | 
| 
      
 70 
     | 
    
         
            +
                User.first.update(certificates_tmp: { deleted_ids: file_ids, files: [File.open('my_file.png')] })
         
     | 
| 
      
 71 
     | 
    
         
            +
              ```
         
     | 
| 
      
 72 
     | 
    
         
            +
               **HTML**
         
     | 
| 
      
 73 
     | 
    
         
            +
              ```haml
         
     | 
| 
      
 74 
     | 
    
         
            +
              = file_field_tag 'user[certificates_tmp][files][]', multiple: true
         
     | 
| 
      
 75 
     | 
    
         
            +
              - user.certificates.each do |file|
         
     | 
| 
      
 76 
     | 
    
         
            +
                %li
         
     | 
| 
      
 77 
     | 
    
         
            +
                  = image_tag(file)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  = check_box_tag 'user[certificates_tmp][deleted_ids][]', value: file.id
         
     | 
| 
      
 79 
     | 
    
         
            +
              ```
         
     | 
| 
      
 80 
     | 
    
         
            +
                
         
     | 
| 
      
 81 
     | 
    
         
            +
            - Removes all certificates before uploading a new one
         
     | 
| 
      
 82 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 83 
     | 
    
         
            +
                User.first.update(certificates_tmp: { clean_before: true, files: [File.open('my_file.png')] })
         
     | 
| 
      
 84 
     | 
    
         
            +
              ```
         
     | 
| 
      
 85 
     | 
    
         
            +
              
         
     | 
| 
      
 86 
     | 
    
         
            +
            - Upload files with custom names (requires `use_filename: true`)
         
     | 
| 
      
 87 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 88 
     | 
    
         
            +
              class User < ApplicationRecord
         
     | 
| 
      
 89 
     | 
    
         
            +
                def photo_filename(filename)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  "#{id}-#{full_name.parameterize}#{File.extname(filename)}"
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
              ```
         
     | 
| 
      
 94 
     | 
    
         
            +
              When `<attr_name>_filename` is defined, then it is called to fetch the uploaded file name.    
         
     | 
| 
      
 95 
     | 
    
         
            +
              Note: Check [this](https://gist.github.com/owen2345/33730a452d73b6b292326bb602b0ee6b) if you want to rename an already uploaded file (remote file)
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
            - Capture event when file upload has failed
         
     | 
| 
      
 98 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 99 
     | 
    
         
            +
                class User < ApplicationRecord
         
     | 
| 
      
 100 
     | 
    
         
            +
                  def ast_delayed_on_error(attr_name, error)
         
     | 
| 
      
 101 
     | 
    
         
            +
                    puts "Failed #{attr_name} with #{error}"
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
              ```
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
            - Capture event when file has been uploaded
         
     | 
| 
      
 107 
     | 
    
         
            +
              ```ruby
         
     | 
| 
      
 108 
     | 
    
         
            +
                class User < ApplicationRecord
         
     | 
| 
      
 109 
     | 
    
         
            +
                  after_save_commit do
         
     | 
| 
      
 110 
     | 
    
         
            +
                    puts 'Photo has been uploaded' if photo.blob.present?
         
     | 
| 
      
 111 
     | 
    
         
            +
                    puts 'No pending enqueued photo uploads' unless photo_delayed_uploads.any?
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
                  
         
     | 
| 
      
 114 
     | 
    
         
            +
                  before_save do 
         
     | 
| 
      
 115 
     | 
    
         
            +
                    puts "current assigned tmp photo: #{photo_tmp.inspect}"
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
              ```
         
     | 
| 
      
 119 
     | 
    
         
            +
              `<attr_name>_delayed_uploads` is a `has_many` association that contains the list of scheduled uploads for the corresponding attribute.
         
     | 
| 
      
 120 
     | 
    
         
            +
              
         
     | 
| 
      
 121 
     | 
    
         
            +
              
         
     | 
| 
      
 122 
     | 
    
         
            +
            ## Preprocessing original files before uploading (Rails 7+)
         
     | 
| 
      
 123 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 124 
     | 
    
         
            +
            class User < ApplicationRecord
         
     | 
| 
      
 125 
     | 
    
         
            +
              has_one_attached :photo do |attachable|
         
     | 
| 
      
 126 
     | 
    
         
            +
                attachable.variant :default, strip: true, quality: 70, resize_to_fill: [200, 200]
         
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
            end
         
     | 
| 
      
 129 
     | 
    
         
            +
            ```
         
     | 
| 
      
 130 
     | 
    
         
            +
            `: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.
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 135 
     | 
    
         
            +
            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.    
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
            To ensure your contribution changes, run the tests with: `docker-compose run test`
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
            ## License
         
     | 
| 
      
 140 
     | 
    
         
            +
            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,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActivestorageDelayed
         
     | 
| 
      
 4 
     | 
    
         
            +
              module DelayedConcern
         
     | 
| 
      
 5 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 6 
     | 
    
         
            +
                included do
         
     | 
| 
      
 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 }
         
     | 
| 
      
 10 
     | 
    
         
            +
                    tmp_attr_name = :"#{attr_name}_tmp"
         
     | 
| 
      
 11 
     | 
    
         
            +
                    has_many_attr = :"#{attr_name}_delayed_uploads"
         
     | 
| 
      
 12 
     | 
    
         
            +
                    attr_accessor tmp_attr_name
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    has_many has_many_attr, as: :uploadable, dependent: :destroy, class_name: 'ActivestorageDelayed::DelayedUpload'
         
     | 
| 
      
 15 
     | 
    
         
            +
                    if required
         
     | 
| 
      
 16 
     | 
    
         
            +
                      validates tmp_attr_name, presence: true, unless: ->(o) { o.send(attr_name).blob }
         
     | 
| 
      
 17 
     | 
    
         
            +
                      validates attr_name, presence: true, unless: ->(o) { o.send(tmp_attr_name) }
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    # @param delayed_data [Hash<files: Array<File1, File2>, deleted_ids: Array<1, 2>, clean_before: Boolean>]
         
     | 
| 
      
 21 
     | 
    
         
            +
                    # @param delayed_data [Array<File1, File2>]
         
     | 
| 
      
 22 
     | 
    
         
            +
                    define_method "#{tmp_attr_name}=" do |delayed_data|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      instance_variable_set(:"@#{tmp_attr_name}", delayed_data.dup)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      delayed_data = { files: delayed_data } unless delayed_data.is_a?(Hash)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      delayed_data[:tmp_files] = delayed_data.delete(:files)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      delayed_data[:deleted_ids] = (delayed_data.delete(:deleted_ids) || []).join(',')
         
     | 
| 
      
 27 
     | 
    
         
            +
                      delayed_data[:attr_name] = attr_name
         
     | 
| 
      
 28 
     | 
    
         
            +
                      send(has_many_attr) << send(has_many_attr).new(delayed_data)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # @param _attr_name (String)
         
     | 
| 
      
 34 
     | 
    
         
            +
                # @param _error (Exception)
         
     | 
| 
      
 35 
     | 
    
         
            +
                def ast_delayed_on_error(_attr_name, _error); end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,93 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ActivestorageDelayed
         
     | 
| 
      
 4 
     | 
    
         
            +
              class DelayedUploader
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :delayed_upload
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(delayed_upload_id)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @delayed_upload = delayed_upload_id if delayed_upload_id.is_a?(ActiveRecord::Base)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @delayed_upload ||= DelayedUpload.find_by(id: delayed_upload_id)
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def call
         
     | 
| 
      
 13 
     | 
    
         
            +
                  return unless delayed_upload
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  remove_files
         
     | 
| 
      
 16 
     | 
    
         
            +
                  upload_photos
         
     | 
| 
      
 17 
     | 
    
         
            +
                  save_changes
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                private
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                # TODO: check the ability to delete io with save or upload method
         
     | 
| 
      
 23 
     | 
    
         
            +
                # file_data['io'].close
         
     | 
| 
      
 24 
     | 
    
         
            +
                def upload_photos # rubocop:disable Metrics/AbcSize
         
     | 
| 
      
 25 
     | 
    
         
            +
                  tmp_files_data.each do |file_data|
         
     | 
| 
      
 26 
     | 
    
         
            +
                    model.send(attr_name).attach(file_data.transform_keys(&:to_sym))
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                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)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def save_changes
         
     | 
| 
      
 34 
     | 
    
         
            +
                  model.save!
         
     | 
| 
      
 35 
     | 
    
         
            +
                  delayed_upload.destroy!
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                # @return [Array<Hash<io: StringIO, filename: String, content_type: String>]
         
     | 
| 
      
 39 
     | 
    
         
            +
                def tmp_files_data
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @tmp_files_data ||= begin
         
     | 
| 
      
 41 
     | 
    
         
            +
                    files = JSON.parse(delayed_upload.files || '[]')
         
     | 
| 
      
 42 
     | 
    
         
            +
                    files.each do |file_data|
         
     | 
| 
      
 43 
     | 
    
         
            +
                      file_data['io'] = base64_to_file(file_data)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      if attr_settings[:use_filename]
         
     | 
| 
      
 45 
     | 
    
         
            +
                        file_data['key'] = filename_for(file_data['filename'])
         
     | 
| 
      
 46 
     | 
    
         
            +
                        file_data['filename'] = file_data['key']
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def base64_to_file(file_data)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  tempfile = Tempfile.new(file_data['filename'])
         
     | 
| 
      
 54 
     | 
    
         
            +
                  tempfile.binmode
         
     | 
| 
      
 55 
     | 
    
         
            +
                  tempfile.write Base64.decode64(file_data['io'])
         
     | 
| 
      
 56 
     | 
    
         
            +
                  tempfile.rewind
         
     | 
| 
      
 57 
     | 
    
         
            +
                  tempfile
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def model
         
     | 
| 
      
 61 
     | 
    
         
            +
                  @model ||= delayed_upload.uploadable
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                def filename_for(filename)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  method_name = "#{attr_name}_filename".to_sym
         
     | 
| 
      
 66 
     | 
    
         
            +
                  return model.send(method_name, filename) if model.respond_to?(method_name)
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  name = File.basename(filename, '.*').parameterize
         
     | 
| 
      
 69 
     | 
    
         
            +
                  name = "#{SecureRandom.uuid}-#{name}" if support_multiple?
         
     | 
| 
      
 70 
     | 
    
         
            +
                  "#{model.id}-#{name}#{File.extname(filename)}"
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def remove_files
         
     | 
| 
      
 74 
     | 
    
         
            +
                  items = delayed_upload.uploadable.send(attr_name)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  return unless support_multiple?
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  items.where(id: delayed_upload.deleted_ids.split(',')).destroy_all if delayed_upload.deleted_ids.present?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  items.destroy_all if delayed_upload.clean_before
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def support_multiple?
         
     | 
| 
      
 82 
     | 
    
         
            +
                  model.send(attr_name).class.name.include?('Many')
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def attr_name
         
     | 
| 
      
 86 
     | 
    
         
            +
                  delayed_upload.attr_name.to_sym
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                def attr_settings
         
     | 
| 
      
 90 
     | 
    
         
            +
                  model.class.instance_variable_get(:@ast_delayed_settings)[attr_name]
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # t.string :attr_name, null: false
         
     | 
| 
      
 4 
     | 
    
         
            +
            # t.string :deleted_ids, default: ''
         
     | 
| 
      
 5 
     | 
    
         
            +
            # t.boolean :clean_before, default: false
         
     | 
| 
      
 6 
     | 
    
         
            +
            # t.text :files
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module ActivestorageDelayed
         
     | 
| 
      
 9 
     | 
    
         
            +
              class DelayedUpload < ActiveRecord::Base
         
     | 
| 
      
 10 
     | 
    
         
            +
                self.table_name = 'activestorage_delayed_uploads'
         
     | 
| 
      
 11 
     | 
    
         
            +
                attr_accessor :tmp_files
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                belongs_to :uploadable, polymorphic: true
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                before_save :parse_tmp_files
         
     | 
| 
      
 16 
     | 
    
         
            +
                after_create_commit do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  ActivestorageDelayed::DelayedUploaderJob.perform_later(id)
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                private
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def parse_tmp_files
         
     | 
| 
      
 23 
     | 
    
         
            +
                  self.files = (tmp_files.is_a?(Array) ? tmp_files : [tmp_files]).select(&:present?).map do |file|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    {
         
     | 
| 
      
 25 
     | 
    
         
            +
                      'io' => Base64.encode64(file.read),
         
     | 
| 
      
 26 
     | 
    
         
            +
                      'filename' => file.try(:original_filename) || File.basename(file.path),
         
     | 
| 
      
 27 
     | 
    
         
            +
                      'content_type' => file.try(:content_type) || Marcel::MimeType.for(file)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    }
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end.to_json
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rails'
         
     | 
| 
      
 4 
     | 
    
         
            +
            module ActivestorageDelayed
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Railtie < ::Rails::Railtie
         
     | 
| 
      
 6 
     | 
    
         
            +
                railtie_name :activestorage_delayed
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                config.after_initialize do |_app|
         
     | 
| 
      
 9 
     | 
    
         
            +
                  require_relative '../../initializers/upload_default_variation'
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'active_storage'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'active_job'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'activestorage-delayed/version'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'activestorage-delayed/railtie'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'activestorage-delayed/delayed_concern'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'activestorage-delayed/delayed_uploader'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'activestorage-delayed/delayed_uploader_job'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'activestorage-delayed/models/delayed_upload'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            module ActivestorageDelayed
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,82 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: activestorage-delayed
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Owen Peredo Diaz
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire:
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2022-04-22 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: activestorage
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: rails
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            description: Ruby on Rails gem to upload activestorage files in background
         
     | 
| 
      
 42 
     | 
    
         
            +
            email:
         
     | 
| 
      
 43 
     | 
    
         
            +
            - owenperedo@gmail.com
         
     | 
| 
      
 44 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 45 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 46 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 47 
     | 
    
         
            +
            files:
         
     | 
| 
      
 48 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 49 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 50 
     | 
    
         
            +
            - lib/activestorage-delayed/delayed_concern.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib/activestorage-delayed/delayed_uploader.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            - lib/activestorage-delayed/delayed_uploader_job.rb
         
     | 
| 
      
 53 
     | 
    
         
            +
            - lib/activestorage-delayed/models/delayed_upload.rb
         
     | 
| 
      
 54 
     | 
    
         
            +
            - lib/activestorage-delayed/railtie.rb
         
     | 
| 
      
 55 
     | 
    
         
            +
            - lib/activestorage-delayed/version.rb
         
     | 
| 
      
 56 
     | 
    
         
            +
            - lib/activestorage_delayed.rb
         
     | 
| 
      
 57 
     | 
    
         
            +
            homepage: https://github.com/owen2345/activestorage-delayed
         
     | 
| 
      
 58 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 59 
     | 
    
         
            +
            metadata:
         
     | 
| 
      
 60 
     | 
    
         
            +
              homepage_uri: https://github.com/owen2345/activestorage-delayed
         
     | 
| 
      
 61 
     | 
    
         
            +
              source_code_uri: https://github.com/owen2345/activestorage-delayed
         
     | 
| 
      
 62 
     | 
    
         
            +
              changelog_uri: https://github.com/owen2345/activestorage-delayed
         
     | 
| 
      
 63 
     | 
    
         
            +
            post_install_message:
         
     | 
| 
      
 64 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 65 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 66 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 67 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 68 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 69 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 70 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 71 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 72 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 73 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 74 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 75 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 76 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 77 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 78 
     | 
    
         
            +
            rubygems_version: 3.1.2
         
     | 
| 
      
 79 
     | 
    
         
            +
            signing_key:
         
     | 
| 
      
 80 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 81 
     | 
    
         
            +
            summary: Ruby on Rails gem to upload activestorage files in background
         
     | 
| 
      
 82 
     | 
    
         
            +
            test_files: []
         
     |