Skip to content

Instantly share code, notes, and snippets.

@ashaninBenjamin
Last active November 12, 2018 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ashaninBenjamin/e7836c6daaa55cab5f507f8fcf678627 to your computer and use it in GitHub Desktop.
Save ashaninBenjamin/e7836c6daaa55cab5f507f8fcf678627 to your computer and use it in GitHub Desktop.
Carrierwave preloading
  • How to preload file via Carrierwave for api?
  • How to preload huge file before sending all form?

Carrierwave doesn't give approach for preloading file, so there is simple implementation.

# config/initializers/carrierwave.rb
ActiveRecord::Base.extend Carrierwave::PreloadAdapter
# app/models/document.rb
class Document < ApplicationRecord
mount_preload_uploader :file, FileUploader
mount_preload_uploaders :files, FileUploader
end
# lib/carrierwave/preload_adapter.rb
module Carrierwave
module PreloadAdapter
def mount_preload_uploader(attribute, uploader_class, **options)
mount_uploader attribute, uploader_class, options
define_method "#{attribute}=" do |data|
uploader = PreloadUploader.build_preloaded(data)
return super(data) if uploader.blank?
@preload_uploaders ||= []
@preload_uploaders << uploader
super(uploader.file)
end
after_save { [*@preload_uploaders].compact.each(&:remove!) }
end
def mount_preload_uploaders(attribute, uploader_class, **options)
mount_uploaders attribute, uploader_class, options
define_method "#{attribute}=" do |data|
uploaders = data.map { |el| PreloadUploader.build_preloaded(el) }.compact
return super(data) if uploaders.blank?
@preload_uploaders ||= []
@preload_uploaders += uploaders
super(uploaders.map(&:file))
end
after_save { [*@preload_uploaders].compact.each(&:remove!) }
end
end
end
# app/uploaders/preload_uploader.rb
class PreloadUploader < CarrierWave::Uploader::Base
OUTCOME_PREFIX = 'preload'.freeze
TIMESTAMP_FORMAT = '%Y%m%d-%H%M%-s'.freeze
storage :file
def self.build_preloaded(data)
return unless data =~ %r{#{OUTCOME_PREFIX}:(\d{8}-\d{14})/(.*)}
folder_name = Regexp.last_match[1]
file_name = Regexp.last_match[2]
instance = new(folder_name)
instance.retrieve_from_store!(file_name)
instance
end
def initialize(folder_name = Time.current.strftime(TIMESTAMP_FORMAT))
@folder_name = folder_name
end
def store_dir
"preloading/#{@folder_name}"
end
def move_to_cache
false
end
def outcome
"#{OUTCOME_PREFIX}:#{@folder_name}/#{filename}"
end
end
Rails.application.routes.draw do
resources :uploads do
post :preload, on: :collection
end
end
# app/controllers/uploads_controller.rb
class UploadsController < ApplicationController
def preload
uploader = PreloadUploader.new
uploader.store!(params[:file])
if uploader.file.present?
render json: { code: :ok, result: uploader.outcome }
else
render json: { code: :error }, status: :unprocessable_entity
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment