Мне нужно изменить некоторые метаданные (Content-Type) на сотни или тысячи объектов на S3. Какой хороший способ сделать это с рубином? Насколько я могу судить, нет возможности сохранить только метаданные с fog.io, весь объект должен быть повторно сохранен. Похоже, что использование официальной библиотеки sdk потребовало бы, чтобы я переместил среду-оболочку только для этой одной задачи.
Как обновить пакет метаданных объектов S3 с использованием ruby?
Ответ 1
Вы правы, официальный SDK позволяет вам изменять метаданные объекта, не загружая его снова. Что он делает, это копировать объект, но на сервере, поэтому вам не нужно загружать файл и повторно загружать его.
Обертка будет легко реализована, что-то вроде
bucket.objects.each do |object|
object.metadata['content-type'] = 'application/json'
end
Ответ 2
В API v2 вы можете использовать Object#copy_from()
или Object.copy_to()
с параметрами :metadata
и :metadata_directive => 'REPLACE'
для обновления метаданных объекта, не загружая их из S3.
Код Joost gist вызывает эту ошибку:
Aws:: S3:: Errors:: InvalidRequest: этот запрос на копирование является незаконным, поскольку он пытается скопировать объект сам по себе, не меняя метаданные, класс хранения, местоположение перенаправления сайтов или шифрование атрибуты.
Это связано с тем, что по умолчанию AWS игнорирует :metadata
, поставляемую с копией, поскольку копирует метаданные. Мы должны установить параметр :metadata_directive => 'REPLACE'
, если мы хотим обновить метаданные на месте.
См. http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#copy_from-instance_method
Вот полный фрагмент рабочего кода, который я недавно использовал для выполнения операций обновления метаданных:
require 'aws-sdk'
# S3 setup boilerplate
client = Aws::S3::Client.new(
:region => 'us-east-1',
:access_key_id => ENV['AWS_ACCESS_KEY'],
:secret_access_key => ENV['AWS_SECRET_KEY'],
)
s3 = Aws::S3::Resource.new(:client => client)
# Get an object reference
object = s3.bucket('my-bucket-name').object('my-object/key')
# Create our new metadata hash. This can be any hash; in this example we update
# existing metadata with a new key-value pair.
new_metadata = object.metadata.merge('MY_NEW_KEY' => 'MY_NEW_VALUE')
# Use the copy operation to replace our metadata
object.copy_to(object,
:metadata => new_metadata,
# IMPORTANT: normally S3 copies the metadata along with the object.
# we must supply this directive to replace the existing metadata with
# the values we supply
:metadata_directive => "REPLACE",
)
Для удобства повторного использования:
def update_metadata(s3_object, new_metadata = {})
s3_object.copy_to(s3_object,
:metadata => new_metadata
:metadata_directive => "REPLACE"
)
end
Ответ 3
Для будущих читателей здесь приведен полный пример изменения материала с использованием Ruby aws-sdk v1 (также см. этот Gist для aws -sdk v2):
# Using v1 of Ruby aws-sdk as currently v2 seems not able to do this (broken?).
require 'aws-sdk-v1'
key = YOUR_AWS_KEY
secret = YOUR_AWS_SECRET
region = YOUR_AWS_REGION
AWS.config(access_key_id: key, secret_access_key: secret, region: region)
s3 = AWS::S3.new
bucket = s3.buckets[bucket_name]
bucket.objects.with_prefix('images/').each do |obj|
puts obj.key
# Add metadata: {} to next line for more metadata.
obj.copy_from(obj.key, content_type: obj.content_type, cache_control: 'max-age=1576800000', acl: :public_read)
end
Ответ 4
после некоторого поиска это, похоже, работает для меня
obj.copy_to(obj, :metadata_directive=>"REPLACE", :acl=>"public-read",:content_type=>"text/plain")