我有一个 Rails 应用程序,当前使用 ActveRecord 通过
has_many_attached :images
将许多图像附加到几个不同的模型。该应用程序开始超出本地 ./storage
目录中这些图像的存储空间,因此我已经开始迁移到 S3 兼容服务的过程。
附加
images
的新记录现在保存到新的 S3 服务,并且在查看记录时可以正确调用图像。我使用 s3cmd
将本地目录中的所有文件同步到新的 S3 服务,似乎成功完成,并将 ./storage
目录重命名为 ./storage.bak
进行测试。
所有预先存在的记录现在都无法从 S3 服务获取关联的图像。我已经从控制台发出了
ActiveStorage::Blob.update_all(service_name: 'digitalocean_s3')
,它确实更新了所有记录的 service_name
,但图像仍然无法加载。有趣的是,当单击这些图像之一的链接时,Digital Ocean(S3 兼容存储桶的主机)显示以下内容(0 和 x 被我替换):
<Error>
<Code>NoSuchKey</Code>
<Message/>
<BucketName>attachments-production</BucketName>
<RequestId>tx000000000000000000000-0000000000-00000000-nyc3d</RequestId>
<HostId>xxxxxxxx-nyc3d-nyc3-xxxx</HostId>
</Error>
我猜我需要改变这些斑点的其他东西,但是什么?我还漏掉了什么吗?
实际上,使用本地
./storage
目录时附件文件的放置位置似乎与使用 S3 存储桶时不同。正如我在上面的回复中所述,当存储在本地存储目录中时,ActiveStorage 使用的是这样的子目录结构:
./storage/va/j4/vaj4us85jdi33jdiw48
但是,当配置为使用 S3 存储桶时,它将所有文件直接存储在存储桶的根目录中,没有模拟目录结构,如下所示:
/vaj4us85jdi33jdiw48
因此,诀窍是将所有这 500,000 多个附件从数千个子目录获取到 S3 存储桶的根目录。我将
s3cmd
与 find
结合使用,使用下面的一行代码来完成此操作:
find /app_dir/storage -type f ! -path "*/variants/*" -exec bash -c 's3cmd sync --preserve "{}" "s3://bucket-name/$(basename "{}")"' \;
这会找到所有文件,无论子目录如何,然后分别为每个文件启动
s3cmd sync
命令并将它们放入存储桶的根目录中。我选择在这里排除 ./storage/variants
目录,我对稍后重新生成的目录没意见。
可能有更有效的方法来做到这一点,但我能够使用这种方法在大约 60 小时内复制 300 GB 的附件,这对于这个项目来说已经足够快了。