0

I've updated my carrierwave uploader to limit image sizes to 2000px. I'm not using any custom version. I want to reprocess all the images that have been previously uploaded. I tried using .recreate_version! but that doesn't seem to work. Is there something else I can do?

uploader

class FileUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  delegate :extension_whitelist, to: :model

  process resize_to_fit: [2000, 2000]

  def filename
    # CarrierWave has already defined @filename
    @_filename ||= generate_random_filename
  end

  def generate_random_filename
    return unless file = model.file&.file

    3.times do
      name = "#{SecureRandom.hex(6)}.#{file.extension}"
      return name unless Attachment.search(file_url_end: name).result.any?
    end

    fail "couldn't find a unique filename!"
  end

  def url(options = {})
    mounted_on = model.send(:_mounter, mounted_as).uploader_options[:mount_on] || mounted_as

    if model.attributes[mounted_on.to_s] =~ /https?:\/\/.+/
      model.attributes[mounted_on.to_s]
    else
      super
    end
  end
end

Attachement

class Attachment < ApplicationRecord
  has_paper_trail

  belongs_to :owner, polymorphic: true

  mount_uploader :file, FileUploader,
    # `mount_on` is used to get around a paper_trail bug where it tries serializing the
    # uploader object, instead of simply the URL itself.
    # https://github.com/modernmsg/modernmsg/pull/2847#issuecomment-199378461
    # http://stackoverflow.com/questions/9423279
    mount_on: :file_url

  # Stores the full URL in the database
  def write_uploader(column, identifier)
    if file._storage == CarrierWave::Storage::AWS
      identifier = CarrierWave::Storage::AWSFile.new(file, file.send(:storage).connection, file.store_path).url
    end

    write_attribute(column, identifier)
  end

  PURPOSES = {
    ...
  }

  MIN_WIDTHS = {
    ...
  }

  validates_inclusion_of :purpose, allow_nil: true, in: -> a { PURPOSES[a.owner.class] || [] }

  # CarrierWave normally starts processing the file immediately as the attribute is set.
  # That's a problem because `extension_whitelist` is determined by the association,
  # which isn't set until after the attributes themselves are set.
  # https://github.com/carrierwaveuploader/carrierwave/issues/361
  # https://github.com/rails/rails/blob/v4.2.5.2/activerecord/lib/active_record/associations/has_many_association.rb#L34-L43
  # rubocop:disable Style/TrivialAccessors
  alias original_file= file=
  def file=(file)
    @file = file
  end
  before_validation :set_file
  def set_file
    self.original_file = @file if @file
  end
  # Then, for the remote URL option
  alias original_remote_file_url= remote_file_url=
  def remote_file_url=(url)
    @remote_file_url = url
  end
  before_validation :set_remote_file_url
  def set_remote_file_url
    self.original_remote_file_url = @remote_file_url if @remote_file_url
  end
  # rubocop:enable Style/TrivialAccessors

  # Don't accidentally override the file if other attributes are updated.
  skip_callback :save, :before,  :write_file_identifier,         unless: :file_url_changed?
  skip_callback :save, :after,   :store_file!,                   unless: :file_url_changed?
  skip_callback :commit, :after, :remove_previously_stored_file, unless: ->{ previous_changes.key? :file_url }

  validates_presence_of :file

  def extension_whitelist
    images = %w[jpg jpeg gif png svg]
    videos = %w[mov mp4]
    promotional_materials = %w[pdf]

    case owner
    when Authentication, Property, Company
      images + promotional_materials
    when Ad
      images + videos
    when User, Profile, Player
      images
    end
  end

  validate :check_min_width
  def check_min_width
    if min_width && file?
      width, height = FastImage.size file.path
      if width < min_width
        errors.add :purpose, "min width for a #{purpose} image is #{min_width} pixels"
      end
    end
  end

  def min_width
    MIN_WIDTHS.dig owner.class, purpose
  end
end

Rake task

# CarrierWave rake tasks
#
# Task:   reprocess
# Desc:   Reprocess all images for the Attachment class
# Usage:  rake carrierwave:reprocess

namespace :carrierwave do
  desc 'Reprocess all images for the Attachment class'
  task reprocess: :environment do
    Attachment.all.each do |a|
      a.file.recreate_versions!
      a.save!
    rescue
      false
    end
  end
end
Antarr Byrd
  • 24,863
  • 33
  • 100
  • 188

1 Answers1

0

In order to reprocess you are going to need to create versions. For CarrierWave, the original file will never be reprocessed, even though you added a global resize_to_fit transformation inside your FileUploader.

To achieve what you are looking for, you can create a new version. I am naming it large.

class FileUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  # ...

  version :large do 
    process resize_to_fit: [2000, 2000]
  end
end

You can now run your rake task. When you look into your S3 folder you will realize you have two files for each uploaded file. One which is the original and another one which is the large version.

Flavio Wuensche
  • 9,460
  • 1
  • 57
  • 54