- 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 |