需要改变存储"目录"在S3存储桶文件(Carrierwave /雷雨)雷雨、文件、目录、QUOT

2023-09-11 09:52:48 作者:二次元男神

我使用Carrierwave有3个独立的模型将照片上传到S3。我一直在上传,这是存储照片在根S3存储桶的默认设置。于是我决定根据型号将它们存储在子目录如/替身,项目/等基于该模型他们从...上传

I am using Carrierwave with 3 separate models to upload photos to S3. I kept the default settings for the uploader, which was to store photos in a root S3 bucket. I then decided to store them in sub-directories according to model name like /avatars, items/, etc. based on the model they were uploaded from...

然后,我注意到,相同名称的文件已被覆盖,当我删除了一个模型记录,照片没有被删除。

Then, I noticed that files of the same name were being overwritten and when I deleted a model record, the photo wasn't being deleted.

因为我已经改变了store_dir从上传特定的设置是这样的:

I've since changed the store_dir from an uploader-specific setup like this:

  def store_dir
    "items"
  end

到一个通用的其中一个存储在模型证件照片(我用蒙戈仅供参考):

to a generic one which stores photo under the model ID (I use mongo FYI):

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

下面谈到的问题。我想已经将所有的照片制作成S3到正确的目录中的S3。从我准备好了,S3没有目录本身。我在耙任务的麻烦。由于我改变了store_dir,Carrierwave正在寻找所有照片$ P $在错误的目录pviously上传。

Here comes the problem. I am trying to move all the photos already into S3 into the proper "directory" within S3. From what I've ready, S3 doesn't have directories per se. I'm having trouble with the rake task. Since i changed the store_dir, Carrierwave is looking for all the photos previously uploaded in the wrong directory.

namespace :pics do
  desc "Fix directory location of pictures on s3"
  task :item_update => :environment do
    connection = Fog::Storage.new({
      :provider                 => 'AWS',
      :aws_access_key_id => 'XXXX',
      :aws_secret_access_key => 'XXX'
    })
    directory = connection.directories.get("myapp-uploads-dev")

    Recipe.all.each do |l|
      if l.images.count > 0
        l.items.each do |i|
          if i.picture.path.to_s != ""
            new_full_path = i.picture.path.to_s
            filename = new_full_path.split('/')[-1].split('?')[0]
            thumb_filename = "thumb_#{filename}"
            original_file_path = "items/#{filename}"
            puts "attempting to retrieve: #{original_file_path}"
            original_thumb_file_path = "items/#{thumb_filename}"
            photo = directory.files.get(original_file_path) rescue nil
            if photo
              puts "we found: #{original_file_path}"
              photo.expires = 2.years.from_now.httpdate
              photo.key = new_full_path
              photo.save
              thumb_photo = directory.files.get(original_thumb_file_path) rescue nil
              if thumb_photo
                puts "we found: #{original_thumb_file_path}"
                thumb_photo.expires = 2.years.from_now.httpdate
                thumb_photo.key = "/uploads/item/picture/#{i.id}/#{thumb_filename}"
                thumb_photo.save
              end
            end
          end
        end
      end
    end
  end
end

所以我在所有的食谱循环,寻找有照片​​的项目,确定老Carrierwave路径,试图用新的基础上,store_dir变化更新。我想,如果我只是更新为新路径photo.key,它会工作,但它不是。

So I'm looping through all the Recipes, looking for items with photos, determining the old Carrierwave path, trying to update it with the new one based on the store_dir change. I thought if I simply updated the photo.key with the new path, it would work, but it's not.

我是什么做错了吗?有没有更好的方式来完成的要求吗?

What am I doing wrong? Is there a better way to accomplish the ask here?

在这里,我就是这样做要得到这个工作...

namespace :pics do
  desc "Fix directory location of pictures"
  task :item_update => :environment do
    connection = Fog::Storage.new({
      :provider                 => 'AWS',
      :aws_access_key_id => 'XXX',
      :aws_secret_access_key => 'XXX'
    })
    bucket = "myapp-uploads-dev"
    puts "Using bucket: #{bucket}"
    Recipe.all.each do |l|
      if l.images.count > 0
        l.items.each do |i|
          if i.picture.path.to_s != ""
            new_full_path = i.picture.path.to_s
            filename = new_full_path.split('/')[-1].split('?')[0]
            thumb_filename = "thumb_#{filename}"
            original_file_path = "items/#{filename}"
            original_thumb_file_path = "items/#{thumb_filename}"
            puts "attempting to retrieve: #{original_file_path}"
            # copy original item
            begin
              connection.copy_object(bucket, original_file_path, bucket, new_full_path, 'x-amz-acl' => 'public-read')
              puts "we just copied: #{original_file_path}"
            rescue
              puts "couldn't find: #{original_file_path}"
            end
            # copy thumb
            begin
              connection.copy_object(bucket, original_thumb_file_path, bucket, "uploads/item/picture/#{i.id}/#{thumb_filename}", 'x-amz-acl' => 'public-read')
              puts "we just copied: #{original_thumb_file_path}"
            rescue
              puts "couldn't find thumb: #{original_thumb_file_path}"
            end

          end
        end
      end
    end
  end
end

也许不是$ P在世界$ pttiest的东西,但它的工作。

Perhaps not the prettiest thing in the world, but it worked.

推荐答案

您需要进行交互与S3对象直接移动至。你可能想看看 copy_object delete_object 在雾的宝石,这就是CarrierWave用来与互动S3。

You need to be interacting with the S3 Objects directly to move them. You'll probably want to look at copy_object and delete_object in the Fog gem, which is what CarrierWave uses to interact with S3.

https://github.com/fog/fog/blob/8ca8a059b2f5dd2abc232dd2d2104fe6d8c41919/lib/fog/aws/requests/storage/copy_object.rb

https://github.com/fog/fog/blob/8ca8a059b2f5dd2abc232dd2d2104fe6d8c41919/lib/fog/aws/requests/storage/delete_object.rb