2011-01-16 31 views
13

Tôi đang làm việc để triển khai Ajax-Upload để tải ảnh lên trong ứng dụng Rails 3 của tôi. Các tài liệu cho biết:Rails 3 nhận dữ liệu bài thô và ghi nó vào tập tin tmp

  1. For IE6-8, Opera, older versions of other browsers you get the file as you normally do with regular form-base uploads.

  2. For browsers which upload file with progress bar, you will need to get the raw post data and write it to the file.

Vì vậy, làm thế nào tôi có thể nhận được các bài dữ liệu thô trong bộ điều khiển của tôi và viết nó vào một tập tin tmp để điều khiển của tôi sau đó có thể xử lý nó? (Trong trường hợp của tôi điều khiển được thực hiện một số thao tác hình ảnh và tiết kiệm để S3.)

Một số thông tin bổ sung:

Như tôi đang cấu hình ngay bây giờ các bài được đi qua các thông số:

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

... và CREATE hành động trông như thế này:

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 

... nhưng tôi nhận được lỗi này:

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

Tôi vừa phát hành một ví dụ về tải lên ajax trong đường ray 3 + Tải lên tại đây: https://github.com/apneadiving/Pic-upload---Crop-in-Ajax. Hy vọng nó có thể giúp – apneadiving

Trả lời

26

Đó là vì params [: qqfile] không phải là đối tượng UploadedFile mà là một chuỗi chứa tên tệp. Nội dung của tệp được lưu trữ trong phần nội dung của yêu cầu (có thể truy cập bằng cách sử dụng request.body.read). Ofcourse, bạn không thể quên tính tương thích ngược, do đó bạn vẫn phải hỗ trợ UploadedFile.

Vì vậy, trước khi bạn có thể xử lý các tập tin trong một cách thống nhất, bạn phải bắt cả hai trường hợp:

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 
+4

Cảm ơn! Điều này làm việc tuyệt vời! Như một bình luận, tôi tìm thấy (sau khi bạn đặt tôi đi đúng hướng) trong trường hợp của tôi ít nhất 'tmp_file = Tempfile.new (tên tệp)' hoạt động tốt như nhau trong khi làm sạch hơn một chút so với mã của bạn dưới '# Tạo một temp lưu ý tệp. Cả hai cách đều hoạt động tốt. Cảm ơn! – Andrew

+0

'f.write params [: qqfile] .read' - điều này phải là' f.write params [: qqfile] .tempfile.read' nếu không thì không có tập tin nào được lưu trữ – Toshe

+0

Không được, UploadedFile # read là một phím tắt cho UploadedFile # tempfile.read để mã không giống nhau trong cả hai trường hợp –

5

thử nó, thêm 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 

trong loại assets_controller này :

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:

01.
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} 
}); 
1

giải pháp khác là:

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

và trong config.ru:

require 'rack/raw_upload' 
use Rack::RawUpload 

và sử dụng params [: file] trong bộ điều khiển.

Các vấn đề liên quan