带有plupload的CarrierWave直接指向s3 - 如何避免冗余下载/上传?

时间:2012-06-22 14:47:03

标签: ruby-on-rails carrierwave

我最近设置了plupload来直接将文件上传到S3。这是使用S3s posting方法结合plupload完成的。

上传完成后,我将加载模型的延迟作业排队,并使用CarrierWave的remote_ [uploader] _url方法将上传的资源分配给模型。我想使用CarrierWave,因为管理多个版本的简单性。这是我的工作(略有编辑,我意识到我可以使用send_later这个简单的例子):

class MediaJob < Struct.new(:medium)
  def perform
    medium.process_file
    medium.save
  end
end

这是process_file方法:

def process_file
  self.remote_file_url = s3_original_url
end

结果是文件最终进出S3三次:

1)使用plupload上传到S3

2)由CarrierWave下载以进行处理

3)保存模型时由CarrierWave重新上传

对于小文件来说,这一切都很好,但在处理较大的文件时却非常昂贵。必须有一种消除#3的方法。我不希望CarrierWave在保存时上传原始文件,因为原始文件已存在。我确实希望上传版本。

3 个答案:

答案 0 :(得分:4)

所以我找到了解决方案。感谢贡献者的开始。我想确保给予应有的信用,但答案比提议的要多得多。

这是有用的......

1)在plupload完成上传到S3之后,我将文件属性(我安装的CarrierWave上传器)分配给S3的返回键。这是通过使用FileUploaded事件将响应发布到另一个操作而在plupload中完成的:

init : {
    FileUploaded: function(up, file, info) {
        $.post('#{media_path}', {s3_response: info.response});
    }
}

2)该操作选择该响应,并通过模型上的方法分配文件属性(或任何已安装的上传者的名称):

def create
  med = Medium.new_from_s3_response(params[:s3_response])
end

def self.new_from_s3_response(response)
  med = Medium.new

  # Grab filename from response use libxml-ruby gem
  xml = XML::Parser.string(response).parse
  node = xml.find_first('//PostResponse/Key')
  med['file'] = node.content
  med.save

  # Queue up a job to have the file downloaded and processed
  # Note that I am using Mongoid so the handy serialization by DelayedJob doesn't work
  Delayed::Job.enqueue MediaJob.new(med.id)
end

3)作业触发并调用process_file,下载原始文件并创建/上传各种版本。请注意,原始文件未上传。任务完成了!

class MediaJob < Struct.new(:medium_id)
  def perform
    medium = Medium.find(medium_id)
    medium.process_file

  end
end  

def process_file
  # Download from S3
  file.cache_stored_file!
  # Convert to sanitized file for creating versions
  file.retrieve_from_cache!(file.cache_name)

  # Loop through versions and create them....
  file.versions.values.each do |uploader|
    uploader.store!
  end
end

我从CarrierWave GitHub页面的wiki条目中获得了创建版本的代码。

答案 1 :(得分:2)

如果您使用update_attribute,则应跳过回调。我不知道载波如何在内部工作,但这就是我想要的:

def process_file
  update_attribute(:remote_file_url, s3_original_url)
end

然后,您可以跳过调用save

另一种方法是将save更改为save(:validate => false)

编辑:您可以使用skip_callback跳过验证http://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html#method-i-skip_callback

答案 2 :(得分:0)

Perhap您可以尝试类似的东西(我也为存储在s3中的CSV文件做了类似的事情)

1. Download the file to your local directory first 

2. Process the the image (create your version) 

3. And then Upload the file to s3 using fog gem separately 

4. update the remote_url  from the url from the fog gem 

这将完成从3到1的步骤

您可以检查Fog documentation以获取s3网址

希望这个帮助