0

I've got a simple rails app that uploads photos to an object with ActiveStorage.

class ProjectAsset < ApplicationRecord
  belongs_to :project
  belongs_to :user

  has_one_attached :asset 

  has_many :comments, dependent: :delete_all
  accepts_nested_attributes_for :comments
  
  #DB columns => :project_id :asset :user_id
end

And stores them on AWS S3:

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

amazon:
  service: S3
  access_key_id: ***
  secret_access_key: *** 
  region: ***
  bucket: ***

I have a simple form:

<%= form_for ProjectAsset.new do |form| %>
  <%= form.hidden_field :project_id, :value => @project.id %>
  <%= form.hidden_field :user_id, :value => current_user.id %>
  <%= form.file_field :asset, multiple: false, direct_upload: true, class: "", onchange: "autoUpload(this);" %>
              
  <%= form.submit 'Add this Photo' %>
       
<% end %>
    

That saves the image and automatically redirects to the appropriate view template.

def create
    @project_asset = ProjectAsset.new(project_asset_params)

    respond_to do |format|
      if @project_asset.save
        format.html { redirect_to project_path(@project_asset.project), notice: "Project asset was successfully created." }
        format.json { render :show, status: :created, location: @project_asset }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @project_asset.errors, status: :unprocessable_entity }
      end
    end
  end

My question is this, and it's kind of a two parter.

  1. How can I have just the image (:asset) that's being uploaded on :create be placed on a Delayed::Job queue and have the rest of the record save and continue the redirect? and
  2. I have the image displayed on the view template after the redirect. This is fine if there's fast enough data transfer, but a nightmare if you're outside of wifi. How can I have the user's local image in storage used as the image until the asset is uploaded fully into S3?
Alex
  • 95
  • 1
  • 8

1 Answers1

0
  1. You most likely cannot delegate the S3 upload to a background job, since it won't have access to the web server's temporary storage, and you probably don't want to pass the binary data in an argument as a string, which could lead to memory issues. The most common solution for this is to use the "direct upload" feature which lets your browser do the uploading to S3, while the rails app only receives its path once uploaded. See https://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads for more details.
  2. The uploaded image is not stored in your local storage by default, this might help: How to save an image to localStorage and display it on the next page?
Bart
  • 2,606
  • 21
  • 32