使用标准S3配置:
AWS_ACCESS_KEY_ID: [AWS ID]
AWS_BUCKET: [bucket name]
AWS_REGION: [region]
AWS_SECRET_ACCESS_KEY: [secret]
我可以使用此Rails 5.2代码将文件上传到S3(使用直接上传)(仅显示相关代码):
form.file_field :my_asset, direct_upload: true
在提交表单后,这将有效地将我的资产置于我的S3存储桶的根目录中。
如何指定前缀(例如"开发/",以便我可以模仿S3上的文件夹)?
答案 0 :(得分:6)
对不起,目前还不行。我建议创建一个专门用于Active Storage的存储桶。
答案 1 :(得分:6)
我当前的解决方法(至少在ActiveStorage引入了在{3}上传递has_one_attached
和has_many_attached
宏的路径的选项之前)是实现move_to method。
所以我让ActiveStorage像往常一样将图像保存到S3(在存储桶的顶部),然后将文件移动到文件夹结构中。
move_to
方法基本上将文件复制到您传递的文件夹结构中,然后删除放在存储桶根目录下的文件。这样您的文件就会在您想要的地方结束。
因此,例如,如果我们存储了驱动程序详细信息:name
和drivers_license
,请保存它们,因为您已经在执行此操作,以便它位于存储桶的顶部。
然后执行以下操作(我把我放在帮助器中):
module DriversHelper
def restructure_attachment(driver_object, new_structure)
old_key = driver_object.image.key
begin
# Passing S3 Configs
config = YAML.load_file(Rails.root.join('config', 'storage.yml'))
s3 = Aws::S3::Resource.new(region: config['amazon']['region'],
credentials: Aws::Credentials.new(config['amazon']['access_key_id'], config['amazon']['secret_access_key']))
# Fetching the licence's Aws::S3::Object
old_obj = s3.bucket(config['amazon']['bucket']).object(old_key)
# Moving the license into the new folder structure
old_obj.move_to(bucket: config['amazon']['bucket'], key: "#{new_structure}")
update_blob_key(driver_object, new_structure)
rescue => ex
driver_helper_logger.error("Error restructuring license belonging to driver with id #{driver_object.id}: #{ex.full_message}")
end
end
private
# The new structure becomes the new ActiveStorage Blob key
def update_blob_key(driver_object, new_key)
blob = driver_object.image_attachment.blob
begin
blob.key = new_key
blob.save!
rescue => ex
driver_helper_logger.error("Error reassigning the new key to the blob object of the driver with id #{driver_object.id}: #{ex.full_message}")
end
end
def driver_helper_logger
@driver_helper_logger ||= Logger.new("#{Rails.root}/log/driver_helper.log")
end
end
更新blob密钥非常重要,以便对密钥的引用不会返回错误。
如果密钥未更新,任何尝试引用图像的功能都会在其前一个位置(位于存储桶顶部)而不是在其新位置中查找。
我在保存文件后立即从我的控制器调用此函数(即在创建操作中),以便即使它不是它也看起来无缝。
虽然这可能不是最好的方法,但它现在可以使用。
仅供参考:根据您提供的示例,new_structure
变量为new_structure = "development/#{driver_object.image.key}"
。
我希望这有帮助! :)
答案 2 :(得分:3)
谢谢你,索尼亚(Sonia)。
我尝试了您的解决方案,效果很好,但是我遇到了覆盖附件的问题。在执行此操作时,我经常会遇到 IntegrityError 。我认为,这和 checksum 处理可能是Rails核心团队不想添加传递路径名功能的原因。这将需要更改上传方法的整个逻辑。
ActiveStorage :: Attached#create_from_blob 方法,也可以接受 ActiveStorage :: Blob 对象。所以我尝试了另一种方法:
在我的用法中,解决方案是这样的:
def attach file # method for attaching in the model
blob_key = destination_pathname(file)
blob = ActiveStorage::Blob.find_by(key: blob_key.to_s)
unless blob
blob = ActiveStorage::Blob.new.tap do |blob|
blob.filename = blob_key.basename.to_s
blob.key = blob_key
blob.upload file
blob.save!
end
end
# Attach method from ActiveStorage
self.file.attach blob
end
由于将完整路径名传递给 Blob 的密钥,我在服务器上收到了所需的文件结构。
答案 3 :(得分:0)
上述解决方案仍然会给出 IntegrityError ,需要使用File.open(file)。谢谢While的想法。
class History < ApplicationRecord
has_one_attached :gs_history_file
def attach(file) # method for attaching in the model
blob_key = destination_pathname(file)
blob = ActiveStorage::Blob.find_by(key: blob_key.to_s)
unless blob
blob = ActiveStorage::Blob.new.tap do |blob|
blob.filename = blob_key.to_s
blob.key = blob_key
#blob.byte_size = 123123
#blob.checksum = Time.new.strftime("%Y%m%d-") + Faker::Alphanumeric.alpha(6)
blob.upload File.open(file)
blob.save!
end
end
# Attach method from ActiveStorage
self.gs_history_file.attach blob
end
def destination_pathname(file)
"testing/filename-#{Time.now}.xlsx"
end
end