attachment_extensions.rb 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # frozen_string_literal: true
  2. module Paperclip
  3. module AttachmentExtensions
  4. def meta
  5. instance_read(:meta)
  6. end
  7. # monkey-patch to avoid unlinking too avoid unlinking source file too early
  8. # see https://github.com/kreeti/kt-paperclip/issues/64
  9. def post_process_style(name, style) # :nodoc:
  10. raise "Style #{name} has no processors defined." if style.processors.blank?
  11. intermediate_files = []
  12. original = @queued_for_write[:original]
  13. # if we're processing the original, close + unlink the source tempfile
  14. intermediate_files << original if name == :original
  15. @queued_for_write[name] = style.processors
  16. .inject(original) do |file, processor|
  17. file = Paperclip.processor(processor).make(file, style.processor_options, self)
  18. intermediate_files << file unless file == original
  19. file
  20. end
  21. unadapted_file = @queued_for_write[name]
  22. @queued_for_write[name] = Paperclip.io_adapters
  23. .for(@queued_for_write[name], @options[:adapter_options])
  24. unadapted_file.close if unadapted_file.respond_to?(:close)
  25. @queued_for_write[name]
  26. rescue Paperclip::Errors::NotIdentifiedByImageMagickError => e
  27. log("An error was received while processing: #{e.inspect}")
  28. (@errors[:processing] ||= []) << e.message if @options[:whiny]
  29. ensure
  30. unlink_files(intermediate_files)
  31. end
  32. # We overwrite this method to support delayed processing in
  33. # Sidekiq. Since we process the original file to reduce disk
  34. # usage, and we still want to generate thumbnails straight
  35. # away, it's the only style we need to exclude
  36. def process_style?(style_name, style_args)
  37. if style_name == :original && instance.respond_to?(:delay_processing_for_attachment?) && instance.delay_processing_for_attachment?(name)
  38. false
  39. else
  40. style_args.empty? || style_args.include?(style_name)
  41. end
  42. end
  43. def storage_schema_version
  44. instance_read(:storage_schema_version) || 0
  45. end
  46. def assign_attributes
  47. super
  48. instance_write(:storage_schema_version, 1)
  49. end
  50. def variant?(other_filename)
  51. return true if original_filename == other_filename
  52. return false if original_filename.nil?
  53. formats = styles.values.filter_map(&:format)
  54. return false if formats.empty?
  55. other_extension = File.extname(other_filename)
  56. formats.include?(other_extension.delete('.')) && File.basename(other_filename, other_extension) == File.basename(original_filename, File.extname(original_filename))
  57. end
  58. def default_url(style_name = default_style)
  59. @url_generator.for_as_default(style_name)
  60. end
  61. STOPLIGHT_THRESHOLD = 10
  62. STOPLIGHT_COOLDOWN = 30
  63. # We overwrite this method to put a circuit breaker around
  64. # calls to object storage, to stop hitting APIs that are slow
  65. # to respond or don't respond at all and as such minimize the
  66. # impact of object storage outages on application throughput
  67. def save
  68. # Don't go through Stoplight if we don't have anything object-storage-oriented to do
  69. return super if @queued_for_delete.empty? && @queued_for_write.empty? && !dirty?
  70. Stoplight('object-storage') { super }.with_threshold(STOPLIGHT_THRESHOLD).with_cool_off_time(STOPLIGHT_COOLDOWN).with_error_handler do |error, handle|
  71. if error.is_a?(Seahorse::Client::NetworkingError)
  72. handle.call(error)
  73. else
  74. raise error
  75. end
  76. end.run
  77. end
  78. end
  79. end
  80. Paperclip::Attachment.prepend(Paperclip::AttachmentExtensions)