将上传的文件从 Active Storage 迁移到 Carrierwave

Migrating uploaded files from Active Storage to Carrierwave

出于各种原因,我正在将我的上传从 ActiveStorage (AS) 迁移到 CarrierWave (CW)。

我正在制作 rake 任务并整理逻辑 - 我对如何将 AS blob 馈送到 CW 文件感到困惑。

我正在尝试这样的事情:

@files.each.with_index(1) do | a, index |

  if a.attachment.attached?

    a.attachment.download do |file|
      a.file = file
    end
    a.save!

  end

end      

这是基于这两个链接:

https://edgeguides.rubyonrails.org/active_storage_overview.html#downloading-files

message.video.open do |file|
  system '/path/to/virus/scanner', file.path
  # ...
end

https://github.com/carrierwaveuploader/carrierwave#activerecord

# like this
File.open('somewhere') do |f|
  u.avatar = f
end

我在本地测试了这个,文件没有通过上传器加载。我的问题是:

红利问题:

您从 attachment.download 块中获得的 file 对象是一个字符串。更准确地说,来自 .download 的响应是文件 "streamed and yielded in chunks"(参见 documentation)。我通过调用 file.class 验证了这一点,以确保 class 符合我的预期。

因此,要解决您的问题,您需要提供一个可以调用 .read 的对象。通常这是使用 Ruby StringIO class.

但是,考虑到 Carrierwave also expects a filename,您可以使用继承 StringIO 的辅助模型来解决它(来自上面链接的博文):

class FileIO < StringIO
  def initialize(stream, filename)
    super(stream)
    @original_filename = filename
  end

  attr_reader :original_filename
end

然后你可以用a.file = FileIO.new(file, 'new_filename')

替换a.file = file

这是我最后的机架任务(基于已接受的答案)- 可以进行调整。对我有用吗:

namespace :carrierwave do
  desc "Import the old AS files into CW"
  task import: :environment do

    @files = Attachment.all

    puts "#{@files.count} files to be processed"
    puts "+" * 50

    @files.each.with_index(1) do | a, index |

      if a.attachment.attached?

        puts "Attachment #{index}:  Key: #{a.attachment.blob.key} ID: #{a.id} Filename: #{a.attachment.blob.filename}"

        class FileIO < StringIO
          def initialize(stream, filename)
            super(stream)
            @original_filename = filename
          end

          attr_reader :original_filename
        end

        a.attachment.download do |file|
           a.file = FileIO.new(file, a.attachment.blob.filename.to_s)
        end
        a.save!
        puts "-" * 50

      end

    end

  end

  desc "Purge the old AS files"
  task purge: :environment do

    @files = Attachment.all

    puts "#{@files.count} files to be processed"
    puts "+" * 50


    @files.each.with_index(1) do | a, index |

      if a.attachment.attached?

        puts "Attachment #{index}:  Key: #{a.attachment.blob.key} ID: #{a.id} Filename: #{a.attachment.blob.filename}"
        a.attachment.purge
        puts "-" * 50
        @count = index

      end

    end

    puts "#{@count} files purged"


  end

end

现在,在我的例子中,我正在逐步执行此操作 - 我已通过此 rake 任务和相关的 MCV 更新对我的 master 进行了分支。如果我的网站在真正的生产中,可能 运行 首先导入 rake 任务,然后确认一切顺利,然后清除旧的 AS 文件。