Last active
April 6, 2022 15:56
-
-
Save owen2345/ca4cabca74e2ceea1589b261dbd9e5d8 to your computer and use it in GitHub Desktop.
Rails ActiveStorage: Add the ability to upload photos in background
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class DelayedUploaderJob < ApplicationJob | |
queue_as :default | |
attr_reader :model, :attr_name | |
def perform(model_klass, id, attr_name) | |
@model = model_klass.constantize.find(id) | |
@attr_name = attr_name | |
upload_photo if tmp_file_data | |
end | |
private | |
def upload_photo | |
data = { io: file_io, filename: tmp_file_data['name'], content_type: tmp_file_data['content_type'] } | |
model.send(attr_name).attach(data) | |
remove_tmp_data | |
file_io.close | |
rescue => e | |
Rails.logger.error("#{self.class.name}-> Failed uploading files: #{e.message}") | |
end | |
def remove_tmp_data | |
model[attr_tmp_data] = nil | |
model.save! | |
end | |
def file_io | |
@file_io ||= StringIO.new(Base64.decode64(tmp_file_data['body'])) | |
end | |
def tmp_file_data | |
@tmp_file_data ||= model[attr_tmp_data] | |
end | |
def attr_tmp_data | |
"tmp_#{attr_name}_data" | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module DelayedFileConcern | |
extend ActiveSupport::Concern | |
included do | |
def self.delayed_attach(attr_name, required: true) | |
tmp_name = "tmp_#{attr_name}".to_sym | |
attr_accessor tmp_name | |
before_validation { parse_tmp_delayed_file(tmp_name) if send(tmp_name) } | |
validates tmp_name, presence: true, unless: ->(o) { o.send(attr_name).blob } if required | |
validates attr_name, presence: true, unless: -> (o) { o.send(tmp_name) } if required | |
after_save_commit do | |
DelayedUploaderJob.perform_later(self.class.name, id, attr_name) if send(tmp_name) | |
send("#{tmp_name}=", nil) if send(tmp_name) | |
end | |
end | |
end | |
def parse_tmp_delayed_file(tmp_name) | |
file = send(tmp_name) | |
body = Base64.encode64(file.read) | |
if file.respond_to?(:original_filename) # fileUploaded | |
content_type = file.content_type | |
name = file.original_filename | |
else # File.open | |
content_type = Marcel::MimeType.for(file) | |
name = File.basename(file.path) | |
end | |
self["#{tmp_name}_data"] = { 'body' => body, 'name' => name, 'content_type' => content_type } | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: photos | |
# | |
# id :integer not null, primary key | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# tmp_file_data :json <<<< THIS IS REQUIRED WHERE TO SAVE TMP_DATA (tmp_<attr_name>_data) | |
class Photo < ApplicationRecord | |
include DelayedFileConcern | |
has_one_attached :file | |
delayed_attach(:file, required: true) | |
end | |
# Sample: | |
photo = Photo.create!(tmp_file: File.open('/my_image.png')) # >> Background job should be scheduled | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment