Set content_type of Fog storage files on s3

2019-05-28 07:44发布

I'm working with Fog and Amazon s3 to manage video and image files. I've been running into a lot of trouble with setting the content_type for my files.

When working from the console, I am able to go through and individually update each file's content_type, and then run save. However, when I try to run an update on all of the files within a specific directory, I don't get an error, but nothing gets updated. I've run multiple different methods, all with the same basic idea, and all set to print "saved!" if the file saves. The methods run properly and print out "saved!", but when I go back and check the files, the content_type is still nil.

Here's an example of what I'm doing:

directory.files.each do |f|
  case f.key.split(".").last
  when "jpg"
    f.content_type = "image/jpeg"
    puts "saved!" if f.save
  when "mov"
    f.content_type = "video/quicktime"
    puts "saved!" if f.save
  end
end

Also, when I go through and individually update each file, the save works and the content_type gets updated, but the data doesn't persist.

For example:

file = directory.files.first
file.content_type = 'video/quicktime'
file.save         # returns true
file.content_type # returns 'video/quicktime'

However, when I go check the file in AWS, the content type is still nil.

Is there a better (persistent) way of going about updating content_type on Fog s3 files? I feel like I must be going about this the wrong way.

Update: Tried using the file#copy method:

directory.files.each do |f|
  content_type = case f.key.split(".").last
  when "jpg"
    "image/jpeg"
  when "mov"
    "video/quicktime"
  end
  puts "copied!" if f.copy(f.directory.key, f.key, { 'Content-Type' => content_type })
end

I got an error:

Excon::Errors::BadRequest: Expected(200) <=> Actual(400 Bad Request)

from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/excon-0.22.1/lib/excon/middlewares/expects.rb:6:in `response_call'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/excon-0.22.1/lib/excon/connection.rb:355:in `response'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/excon-0.22.1/lib/excon/connection.rb:249:in `request'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/core/connection.rb:21:in `request'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/aws/storage.rb:506:in `request'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/aws/requests/storage/copy_object.rb:33:in `copy_object'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/aws/models/storage/file.rb:93:in `copy'
from (irb):14
from /Users/marybethlee/.rvm/rubies/ruby-2.0.0-p0/bin/irb:16:in `<main>'

2条回答
小情绪 Triste *
2楼-- · 2019-05-28 08:13

If you are just updating metadata (and not the body/content itself) you probably want to use copy instead of save. This is perhaps non-obvious, but that keeps the operation on the S3 side so that it will be MUCH faster.

The signature for copy looks like:

copy(target_directory_key, target_file_key, options = {})

So I think my proposed solution should look (more or less) like this:

directory.files.each do |f|
  content_type = case f.key.split(".").last
  when "jpg"
    "image/jpeg"
  when "mov"
    "video/quicktime"
  end
  options = {
    'Content-Type' => content_type,
    'x-amz-metadata-directive' => 'REPLACE'
  }
  puts "copied!" if f.copy(f.directory, f.key, options)
end

That should basically tell S3 "copy my file over the top of itself, but change this header". That way you don't have to download/reupload the file. This is probably the approach you want.

So, solution aside, still seems like you found a bug. Could you include an example of what you mean by "individually update each file"? Just want to make sure I know exactly what you mean and that I can see the working/non-working cases side by side. Also, how/why do you think it isn't updating the content-type (it might actually be updating it, but just not displaying the updated value correctly, or something like that). Bonus points if you can create an issue here to make sure I don't forget to address it: https://github.com/fog/fog/issues?state=open

查看更多
混吃等死
3楼-- · 2019-05-28 08:20

I found this workaround to get the content type:

directory.files.head(file.key).content_type

where file.key is the name of your file.

查看更多
登录 后发表回答