Skip to content

Commit

Permalink
[breaking] Change to preserve successful files even if others failed
Browse files Browse the repository at this point in the history
  • Loading branch information
mshibuya committed Jun 18, 2019
1 parent 8f18a95 commit 7db9195
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 81 deletions.
30 changes: 21 additions & 9 deletions lib/carrierwave/mount.rb
Expand Up @@ -185,6 +185,18 @@ def #{column}_identifier
_mounter(:#{column}).read_identifiers[0]
end
def #{column}_integrity_error
#{column}_integrity_errors.last
end
def #{column}_processing_error
#{column}_processing_errors.last
end
def #{column}_download_error
#{column}_download_errors.last
end
def store_previous_changes_for_#{column}
attribute_changes = ::ActiveRecord.version.to_s.to_f >= 5.1 ? saved_changes : changes
@_previous_changes_for_#{column} = attribute_changes[_mounter(:#{column}).serialization_column]
Expand Down Expand Up @@ -240,9 +252,9 @@ def remove_previously_stored_#{column}
# [store_images!] Stores all files that have been assigned with +images=+
# [remove_images!] Removes the uploaded file from the filesystem.
#
# [images_integrity_error] Returns an error object if the last files to be assigned caused an integrity error
# [images_processing_error] Returns an error object if the last files to be assigned caused a processing error
# [images_download_error] Returns an error object if the last files to be remotely assigned caused a download error
# [image_integrity_errors] Returns error objects of files which failed to pass integrity check
# [image_processing_errors] Returns error objects of files which failed to be processed
# [image_download_errors] Returns error objects of files which failed to be downloaded
#
# [image_identifiers] Reads out the identifiers of the files
#
Expand Down Expand Up @@ -395,16 +407,16 @@ def store_#{column}!
_mounter(:#{column}).store!
end
def #{column}_integrity_error
_mounter(:#{column}).integrity_error
def #{column}_integrity_errors
_mounter(:#{column}).integrity_errors
end
def #{column}_processing_error
_mounter(:#{column}).processing_error
def #{column}_processing_errors
_mounter(:#{column}).processing_errors
end
def #{column}_download_error
_mounter(:#{column}).download_error
def #{column}_download_errors
_mounter(:#{column}).download_errors
end
def mark_remove_#{column}_false
Expand Down
78 changes: 40 additions & 38 deletions lib/carrierwave/mounter.rb
Expand Up @@ -3,14 +3,17 @@ module CarrierWave
# this is an internal class, used by CarrierWave::Mount so that
# we don't pollute the model with a lot of methods.
class Mounter #:nodoc:
attr_reader :column, :record, :remote_urls, :integrity_error,
:processing_error, :download_error
attr_reader :column, :record, :remote_urls, :integrity_errors,
:processing_errors, :download_errors
attr_accessor :remove, :remote_request_headers

def initialize(record, column, options={})
@record = record
@column = column
@options = record.class.uploader_options[column]
@download_errors = []
@processing_errors = []
@integrity_errors = []
end

def uploader_class
Expand Down Expand Up @@ -41,25 +44,18 @@ def cache(new_files)
return if new_files.blank?
old_uploaders = uploaders
@uploaders = new_files.map do |new_file|
if new_file.is_a?(String)
uploader = old_uploaders.detect { |uploader| uploader.identifier == new_file }
uploader.staged = true if uploader
uploader
else
uploader = blank_uploader
uploader.cache!(new_file)
uploader
handle_error do
if new_file.is_a?(String)
uploader = old_uploaders.detect { |uploader| uploader.identifier == new_file }
uploader.staged = true if uploader
uploader
else
uploader = blank_uploader
uploader.cache!(new_file)
uploader
end
end
end.compact

@integrity_error = nil
@processing_error = nil
rescue CarrierWave::IntegrityError => e
@integrity_error = e
raise e unless option(:ignore_integrity_errors)
rescue CarrierWave::ProcessingError => e
@processing_error = e
raise e unless option(:ignore_processing_errors)
end

def cache_names
Expand All @@ -70,36 +66,29 @@ def cache_names=(cache_names)
return if cache_names.blank?
clear_unstaged
cache_names.map do |cache_name|
uploader = blank_uploader
uploader.retrieve_from_cache!(cache_name)
@uploaders << uploader
begin
uploader = blank_uploader
uploader.retrieve_from_cache!(cache_name)
@uploaders << uploader
rescue CarrierWave::InvalidParameter
# ignore
end
end
rescue CarrierWave::InvalidParameter
end

def remote_urls=(urls)
return if urls.blank? || urls.all?(&:blank?)

@remote_urls = urls
@download_error = nil
@integrity_error = nil

clear_unstaged
urls.zip(remote_request_headers || []).map do |url, header|
uploader = blank_uploader
uploader.download!(url, header || {})
@uploaders << uploader
handle_error do
uploader = blank_uploader
uploader.download!(url, header || {})
@uploaders << uploader
end
end

rescue CarrierWave::DownloadError => e
@download_error = e
raise e unless option(:ignore_download_errors)
rescue CarrierWave::ProcessingError => e
@processing_error = e
raise e unless option(:ignore_processing_errors)
rescue CarrierWave::IntegrityError => e
@integrity_error = e
raise e unless option(:ignore_integrity_errors)
end

def store!
Expand Down Expand Up @@ -172,5 +161,18 @@ def clear_unstaged
@uploaders ||= []
@uploaders.keep_if(&:staged)
end

def handle_error
yield
rescue CarrierWave::DownloadError => e
@download_errors << e
raise e unless option(:ignore_download_errors)
rescue CarrierWave::ProcessingError => e
@processing_errors << e
raise e unless option(:ignore_processing_errors)
rescue CarrierWave::IntegrityError => e
@integrity_errors << e
raise e unless option(:ignore_integrity_errors)
end
end # Mounter
end # CarrierWave
6 changes: 3 additions & 3 deletions lib/carrierwave/validations/active_model.rb
Expand Up @@ -11,7 +11,7 @@ module ActiveModel
class ProcessingValidator < ::ActiveModel::EachValidator

def validate_each(record, attribute, value)
if e = record.__send__("#{attribute}_processing_error")
record.__send__("#{attribute}_processing_errors").each do |e|
message = (e.message == e.class.to_s) ? :carrierwave_processing_error : e.message
record.errors.add(attribute, message)
end
Expand All @@ -21,7 +21,7 @@ def validate_each(record, attribute, value)
class IntegrityValidator < ::ActiveModel::EachValidator

def validate_each(record, attribute, value)
if e = record.__send__("#{attribute}_integrity_error")
record.__send__("#{attribute}_integrity_errors").each do |e|
message = (e.message == e.class.to_s) ? :carrierwave_integrity_error : e.message
record.errors.add(attribute, message)
end
Expand All @@ -31,7 +31,7 @@ def validate_each(record, attribute, value)
class DownloadValidator < ::ActiveModel::EachValidator

def validate_each(record, attribute, value)
if e = record.__send__("#{attribute}_download_error")
record.__send__("#{attribute}_download_errors").each do |e|
message = (e.message == e.class.to_s) ? :carrierwave_download_error : e.message
record.errors.add(attribute, message)
end
Expand Down

0 comments on commit 7db9195

Please sign in to comment.