This tutorial allow you to migrate the Paperclip that uses Hash in the file name to Carrierwave. I will not give all the details but I will give the before and after at the end of this tutorial.
In my case the config of the upload with Paperclip was:
class SomeAttachment < ActiveRecord::Base
  has_attached_file :attachment,
                    validate_media_type: false,
                    url: "/#{Rails.env}/:class/:id/:basename-:hash.:extension",
                    path: "/#{Rails.env}/:class/:id/:basename-:hash.:extension",
                    hash_secret: Rails.application.secrets.secret_key_base.to_s,
                    s3_permissions: :private
endIt was saving the raw file name at attachment_file_name but to migrate to Carrierwave
and to access the file properly we need to save the file name with the generated hash (Paperclip does that).
To do that, I created a new column called attachment_file_name_with_hash and ruuned this script:
SomeAttachment.find_each do |attachment|
  attachment.update_column(:attachment_file_name_with_hash, attachment.attachment.path.split('/').last)
endI created the new attachment column:
add_column :some_attachments, :attachment, :stringAnd migrated the values in a migration:
execute(<<-SQL)
  update some_attachments
  set attachment = attachment_file_name_with_hash;
SQLFinaly when creating the Carrierwave uploader, don't forget to set the store_dir equals to the Paperclip config.
In my case:
def store_dir
  "#{Rails.env}/#{model.class.to_s.underscore.pluralize}/#{model.id}"
endclass AbsenceJustificationAttachment < ActiveRecord::Base
  belongs_to :absence_justification
  has_attached_file :attachment,
                    validate_media_type: false,
                    url: "/#{Rails.env}/:class/:id/:basename-:hash.:extension",
                    path: "/#{Rails.env}/:class/:id/:basename-:hash.:extension",
                    hash_secret: Rails.application.secrets.secret_key_base.to_s,
                    s3_permissions: :private
  validates_attachment_file_name :attachment, matches: [/png\z/, /jpeg\z/, /jpg\z/, /gif\z/, /pdf\z/, /odt\z/,
                                                        /doc\z/, /docx\z/, /ods\z/, /xls\z/, /xlsx\z/, /odp\z/,
                                                        /ppt\z/, /pptx\z/, /odg\z/, /xml\z/, /csv\z/]
  validates_with AttachmentSizeValidator, attributes: :attachment, less_than: 3.megabytes
  validates :attachment, presence: true
endclass AbsenceJustificationAttachment < ActiveRecord::Base
  belongs_to :absence_justification
  mount_uploader :attachment, DocUploader
  validates :attachment, presence: true
  def filename
    attachment&.path&.split('/')&.last
  end
endclass DocUploader < CarrierWave::Uploader::Base
  def store_dir
    "#{Rails.env}/#{model.class.to_s.underscore.pluralize}/#{model.id}"
  end
  def extension_white_list
    %w[png jpeg jpg gif pdf odt doc docx ods xls xlsx odp ppt pptx odg xml csv]
  end
  def filename
    original = original_filename.split(".")[0..-2].join(".")
    "#{original} - #{secure_token}.#{file.extension}" if original_filename.present?
  end
  protected
  def secure_token
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) || model.instance_variable_set(var, SecureRandom.uuid)
  end
end
You can specify you're coming from paperclip with something like this:
this would support paperclips way of defining upload and download locations, hence not breaking previous uploads.
See more here: https://www.rubydoc.info/github/jnicklas/carrierwave/CarrierWave/Compatibility/Paperclip