Rails - Paper_Clip - Поддержка загрузки нескольких файлов - PullRequest
5 голосов
/ 23 октября 2010

У меня установлено paper_clip в моем приложении на Rails 3, и я могу загрузить файл - это было весело и просто!

Теперь задача состоит в том, чтобы позволить пользователю загружать несколько объектов.Будь то выбор файла и возможность выбора более одного.Или нажмите кнопку «еще» и получите другую кнопку загрузки файла.

Я не могу найти учебники или самоцветы, чтобы поддержать это из коробки.Шокирующее я знаю ...

Любые предложения или решения.Похоже на общую потребность?

Спасибо

Ответы [ 3 ]

5 голосов
/ 23 октября 2010

Хорошо, это сложно, но выполнимо.Вот как я заставил это работать.

На стороне клиента я использовал http://github.com/valums/file-uploader, библиотеку javascript, которая позволяет загружать несколько файлов с помощью индикатора выполнения и перетаскивания.Он хорошо поддерживается, легко настраивается, и базовая реализация проста:

В представлении:

<div id='file-uploader'><noscript><p>Please Enable JavaScript to use the file uploader</p></noscript></div>

В js:

var uploader = new qq.FileUploader({
   element: $('#file-uploader')[0],
   action: 'files/upload',
   onComplete: function(id, fileName, responseJSON){
     // callback
   }
});

При передаче файлов FileUploaderотправляет их на сервер в виде запроса XHR, где тело POST представляет собой необработанные данные файла, а заголовки и имя файла передаются в строке URL (это единственный способ загрузить файл асинхронно с помощью javascript).

Вот где все усложняется, поскольку Paperclip понятия не имеет, что делать с этими необработанными запросами, вам нужно отлавливать и преобразовывать их обратно в стандартные файлы (предпочтительно до того, как они попадут в ваше приложение Rails), так что Paperclipможет работать, это волшебство.Это делается с помощью некоторого промежуточного программного обеспечения Rack, которое создает новый Tempfile (помните: Heroku только для чтения):

# Embarrassing note: This code was adapted from an example I found somewhere online
# if you recoginize any of it please let me know so I pass credit.
module Rack
  class RawFileStubber

    def initialize(app, path=/files\/upload/) # change for your route, careful.
      @app, @path = app, path
    end

    def call(env)
      if env["PATH_INFO"] =~ @path
        convert_and_pass_on(env)
      end
      @app.call(env)
    end

    def convert_and_pass_on(env)
      tempfile = env['rack.input'].to_tempfile      
      fake_file = {
        :filename => env['HTTP_X_FILE_NAME'],
        :type => content_type(env['HTTP_X_FILE_NAME']),
        :tempfile => tempfile
      }
      env['rack.request.form_input'] = env['rack.input']
      env['rack.request.form_hash'] ||= {}
      env['rack.request.query_hash'] ||= {}
      env['rack.request.form_hash']['file'] = fake_file
      env['rack.request.query_hash']['file'] = fake_file
      if query_params = env['HTTP_X_QUERY_PARAMS']
        require 'json'
        params = JSON.parse(query_params)
        env['rack.request.form_hash'].merge!(params)
        env['rack.request.query_hash'].merge!(params)
      end
    end

    def content_type(filename)
      case type = (filename.to_s.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
      when %r"jp(e|g|eg)"            then "image/jpeg"
      when %r"tiff?"                 then "image/tiff"
      when %r"png", "gif", "bmp"     then "image/#{type}"
      when "txt"                     then "text/plain"
      when %r"html?"                 then "text/html"
      when "js"                      then "application/js"
      when "csv", "xml", "css"       then "text/#{type}"
      else 'application/octet-stream'
      end
    end
  end
end

Позже, в application.rb:

config.middleware.use 'Rack::RawFileStubber'

Затем в контроллере:

  def upload
    @foo = modelWithPaperclip.create({ :img => params[:file] })
  end

Это работает надежно, хотя может быть медленным процессом при одновременной загрузке большого количества файлов.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ

Это былореализовано для проекта с одним известным и надежным внутренним пользователем.Это почти наверняка имеет серьезные последствия для производительности приложения Heroku с высоким трафиком, и я не проверял его на безопасность.Тем не менее, это определенно работает.

4 голосов
/ 13 марта 2012

Метод, который Райан Бигг рекомендует здесь:

Рекомендация file-uploader Даниэля Менделя действительно великолепна. Это серьезно удивительный пользовательский опыт, такой как загрузка Gmail с помощью перетаскивания. Кто-то написал сообщение в блоге о том, как связать его с приложением rails с использованием промежуточного программного обеспечения rack-raw-upload, если вы заинтересованы в современном компоненте промежуточного программного обеспечения.

Есть также еще один плагин, который был недавно обновлен и который может быть полезен

И еще один (включен для полноты. Я не исследовал этот.)

Эти вопросы тесно связаны

0 голосов
/ 23 октября 2010

Я рассматриваю это в Rails 3 в главе 8 * Action. 1002 *. Однако я не рассматриваю загрузку на S3 или изменение размеров изображений.

Рекомендовать вам покупать его только на основе решения этой единственной проблемы, может показаться немного предвзятым, но я могу лишь гарантировать, что он ответит на другие ваши вопросы. В качестве одной из основных тем он использует подход, основанный на поведенческих разработках, который знакомит вас с функциями Rails при разработке приложения. Это показывает вам не только, как вы можете построить приложение, но и сделать его поддерживаемым .

Что касается изменения размера изображений после их загрузки, у Paperclip есть довольно хорошая документация по этому . Я бы порекомендовал прочитать, а затем задать еще один вопрос по SO, если вы не понимаете ни одного из параметров / методов.

А что касается загрузки S3, вы можете сделать это:

has_attached_file :photo, :styles => { ... }, :storage => :s3

Вам нужно настроить Paperclip::Storage::S3 с вашими данными S3, чтобы настроить его, и снова Paperclip получил довольно классную документацию для этого.

Удачи!

...