2009-11-01 55 views
1

我正在運行一個Rails應用程序,使用Paperclip來處理文件附件和圖像大小調整等。該應用程序當前託管在EngineYard雲上,並且所有附件都存儲在他們的EBS中。考慮使用S3來處理所有Paperclip附件。將數據從EC2轉換爲S3?

有沒有人知道這種遷移的好方法?非常感謝!

回答

3

您可以處理一個rake任務,該任務遍歷您的附件並將它們推送到S3。我一會兒用attachment_fu來使用這個 - 不會有太大的不同。這使用aws-s3寶石。

基本過程:1。 從數據庫中選擇文件需要它們被移動 2.按到S3 3.更新數據庫,以反映該文件不再本地存儲(這樣你可以做他們分批並且不需要擔心兩次推送相同的文件)。

@attachments = Attachment.stored_locally 
@attachments.each do |attachment| 

    base_path = RAILS_ROOT + '/public/assets/' 
    attachment_folder = ((attachment.respond_to?(:parent_id) && attachment.parent_id) || attachment.id).to_s 
    full_filename = File.join(base_path, ("%08d" % attachment_folder).scan(/..../), attachment.filename) 
    require 'aws/s3' 

    AWS::S3::Base.establish_connection!(
    :access_key_id  => S3_CONFIG[:access_key_id], 
    :secret_access_key => S3_CONFIG[:secret_access_key] 
) 

    AWS::S3::S3Object.store(
    'assets/' + attachment_folder + '/' + attachment.filename, 
    File.open(full_filename), 
    S3_CONFIG[:bucket_name], 
    :content_type => attachment.content_type, 
    :access => :private 
) 

    if AWS::S3::Service.response.success? 
    # Update the database 
    attachment.update_attribute(:stored_on_s3, true) 

    # Remove the file on the local filesystem 
    FileUtils.rm full_filename 

    # Remove directory also if it is now empty 
    Dir.rmdir(File.dirname(full_filename)) if (Dir.entries(File.dirname(full_filename))-['.','..']).empty? 
    else 
    puts "There was a problem uploading " + full_filename 
    end 
end 
3

,我發現自己在同樣的情況,把bensie的代碼,並使其成爲自己的工作 - 這是我想出了:

require 'aws/s3' 

# Ensure you do the following: 
# export AMAZON_ACCESS_KEY_ID='your-access-key' 
# export AMAZON_SECRET_ACCESS_KEY='your-secret-word-thingy' 
AWS::S3::Base.establish_connection! 


@failed = [] 
@attachments = Asset.all # Asset paperclip attachment is: has_attached_file :attachment.... 
@attachments.each do |asset| 
    begin 
    puts "Processing #{asset.id}" 
    base_path = RAILS_ROOT + '/public/' 
    attachment_folder = ((asset.respond_to?(:parent_id) && asset.parent_id) || asset.id).to_s 
    styles = asset.attachment.styles.keys 
    styles << :original 
    styles.each do |style| 
     full_filename = File.join(base_path, asset.attachment.url(style, false)) 


     AWS::S3::S3Object.store(
     'attachments/' + attachment_folder + '/' + style.to_s + "/" + asset.attachment_file_name, 
     File.open(full_filename), 
     "swellnet-assets", 
     :content_type => asset.attachment_content_type, 
     :access => (style == :original ? :private : :public_read) 
    ) 

     if AWS::S3::Service.response.success?   
     puts "Stored #{asset.id}[#{style.to_s}] on S3..." 
     else 
     puts "There was a problem uploading " + full_filename 
     end 
    end 
    rescue 
    puts "Error with #{asset.id}" 
    @failed << asset.id 
    end 
end 

puts "Failed uploads: #{@failed.join(", ")}" unless @failed.empty? 

當然,如果你有多個型號,你會需要根據需要進行調整...