【问题标题】:Need to change the storage "directory" of files in an S3 Bucket (Carrierwave / Fog)需要更改 S3 存储桶中文件的存储“目录”(Carrierwave / Fog)
【发布时间】:2013-09-26 21:08:21
【问题描述】:

我正在使用带有 3 个独立模型的 Carrierwave 将照片上传到 S3。我保留了上传器的默认设置,即将照片存储在根 S3 存储桶中。然后,我决定根据模型名称(例如 /avatars、items/ 等)根据它们上传的模型将它们存储在子目录中......

然后,我注意到同名文件被覆盖,当我删除模型记录时,照片并没有被删除。

我已经从上传者特定的设置中更改了 store_dir,如下所示:

  def store_dir
    "items"
  end

到一个在模型 ID 下存储照片的通用的(我使用 mongo 仅供参考):

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

问题来了。我正在尝试将所有已经进入 S3 的照片移动到 S3 中正确的“目录”中。根据我的准备,S3 本身没有目录。我在执行 rake 任务时遇到问题。由于我更改了 store_dir,Carrierwave 正在查找之前上传到错误目录中的所有照片。

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,它会起作用,但事实并非如此。

我做错了什么?有没有更好的方法来完成这里的问题?

这是我为使其正常工作所做的工作...

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

也许不是世界上最漂亮的东西,但它确实有效。

【问题讨论】:

  • 我希望它也能正常工作。是否有错误或文件在您期望的地方不存在?如果数量较少,这可能会很好,但特别是对于较大的数量,您可能希望使用 copy_object,正如 jeremy 下面提到的那样(因为它可以更快地完成所有操作,并且您无需下载任何内容)。
  • 谢谢你,这对我经历同样的事情很有帮助。您将来可能想知道的一件事是您可以直接获取文件名而无需解析路径:i.picture.file.filename 会在您的情况下这样做。

标签: ruby-on-rails ruby-on-rails-3 amazon-s3 carrierwave fog


【解决方案1】:

您需要直接与 S3 对象交互才能移动它们。您可能希望查看 Fog gem 中的 copy_objectdelete_object,这是 CarrierWave 用来与 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

【讨论】:

  • 感谢 Jeremy 的帮助,这让我走上了正确的道路。现在将我的解决方案作为编辑发布给其他来到这里的人。
猜你喜欢
  • 2012-03-21
  • 1970-01-01
  • 2020-06-16
  • 2019-11-07
  • 2013-04-13
  • 1970-01-01
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
相关资源
最近更新 更多