Rails 3获取原始发布数据并将其写入tmp文件

我正在努力实现Ajax-Upload以在我的Rails 3应用程序中上传照片。 文件说:

  1. 对于IE6-8,Opera,其他浏览器的旧版本,您可以像平常的基于表单的上传一样获得该文件。

  2. 对于使用进度条上传文件的浏览器,您需要获取原始发布数据并将其写入文件。

那么,我如何在控制器中接收原始发布数据并将其写入tmp文件,以便我的控制器可以处理它? (在我的情况下,控制器正在进行一些图像处理并保存到S3。)

一些额外的信息:

正如我现在配置的那样,post正在传递这些参数:

Parameters: {"authenticity_token"=>"...", "qqfile"=>"IMG_0064.jpg"} 

…并且CREATE操作如下所示:

 def create @attachment = Attachment.new @attachment.user = current_user @attachment.file = params[:qqfile] if @attachment.save! respond_to do |format| format.js { render :text => '{"success":true}' } end end end 

…但是我收到了这个错误:

 ActiveRecord::RecordInvalid (Validation failed: File file name must be set.): app/controllers/attachments_controller.rb:7:in `create' 

这是因为params [:qqfile]不是UploadedFile对象,而是包含文件名的String。 文件的内容存储在请求的主体中(可以使用request.body.read访问)。 当然,你不能忘记向后兼容性,所以你仍然需要支持UploadedFile。

因此,在您以统一的方式处理文件之前,您必须捕获这两种情况:

 def create ajax_upload = params[:qqfile].is_a?(String) filename = ajax_upload ? params[:qqfile] : params[:qqfile].original_filename extension = filename.split('.').last # Creating a temp file tmp_file = "#{Rails.root}/tmp/uploaded.#{extension}" id = 0 while File.exists?(tmp_file) do tmp_file = "#{Rails.root}/tmp/uploaded-#{id}.#{extension}" id += 1 end # Save to temp file File.open(tmp_file, 'wb') do |f| if ajax_upload f.write request.body.read else f.write params[:qqfile].read end end # Now you can do your own stuff end 

试试吧,添加lib / qq_file.rb:

 # encoding: utf-8 require 'digest/sha1' require 'mime/types' # Usage (paperclip example) # @asset.data = QqFile.new(params[:qqfile], request) class QqFile < ::Tempfile def initialize(filename, request, tmpdir = Dir::tmpdir) @original_filename = filename @request = request super Digest::SHA1.hexdigest(filename), tmpdir fetch end def self.parse(*args) return args.first unless args.first.is_a?(String) new(*args) end def fetch self.write @request.raw_post self.rewind self end def original_filename @original_filename end def content_type types = MIME::Types.type_for(@request.content_type) types.empty? ? @request.content_type : types.first.to_s end end 

在assets_controller中输入:

 def create @asset ||= Asset.new(params[:asset]) @asset.assetable_type = params[:assetable_type] @asset.assetable_id = params[:assetable_id] || 0 @asset.guid = params[:guid] @asset.data = QqFile.parse(params[:qqfile], request) @asset.user_id = 0 @success = @asset.save respond_with(@asset) do |format| format.html { render :text => "{'success':#{@success}}" } format.xml { render :xml => @asset.to_xml } format.js { render :text => "{'success':#{@success}}"} format.json { render :json => {:success => @success} } end end 

JavaScript的:

 var photo_uploader = new qq.FileUploader({ element: document.getElementById('photo-button'), multiple: true, action: '/assets', allowedExtensions: ['png', 'gif', 'jpg', 'jpeg'], sizeLimit: 2097152, params: {guid: $('#idea_guid').val(), assetable_type: 'Idea', klass: 'Picture', collection: true} }); 

另一种解决方案是

 gem 'rack-raw-upload', :git => 'git://github.com/tb/rack-raw-upload.git' 

并在config.ru:

  require 'rack/raw_upload' use Rack::RawUpload 

并在控制器中使用params [:file]。

您可以使用StringIO,而不是创建一些混乱的临时文件。 请参阅我关于CarrierWave的答案,请访问: https ://stackoverflow.com/a/8812976/478354