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

And*_*rew 13 ruby-on-rails http-post ruby-on-rails-3

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

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

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

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

一些额外的信息:

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

Parameters:
{"authenticity_token"=>"...", "qqfile"=>"IMG_0064.jpg"}
Run Code Online (Sandbox Code Playgroud)

...并且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
Run Code Online (Sandbox Code Playgroud)

...但我收到此错误:

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

Ste*_*man 27

这是因为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
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!这很棒!作为一个评论,我发现(在你让我走上正确的轨道之后),在我的情况下,至少`tmp_file = Tempfile.new(filename)`同样有效,同时比`#Creating a temp下的代码更清洁文件`注意.两种方式都很好.谢谢! (4认同)

sup*_*r_p 5

试试吧,添加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
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

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}
});
Run Code Online (Sandbox Code Playgroud)