Генерация файлов и загрузка в формате zip с использованием RubyZip - PullRequest
0 голосов
/ 05 февраля 2019

Для моего проекта Ruby on Rails (Rails версии 5.1.2) я генерирую файлы изображений (png) и загружаю их в виде zip-файла, используя гем RubyZip.

Файлы изображений не хранятся ни в одном каталоге.У меня есть модель под названием Attachment.Каждое вложение имеет атрибут image_string, который является строкой base64 для изображения.Вы можете показывать изображения, используя тег типа image_tag(src = "data:image/jpeg;base64, #{attachment.image_string}", style: "border-radius: 0;")

. Для нескольких изображений я хочу создать временный файл для каждого из них, не сохраняя их в любом месте, и загрузить эти изображения в виде zip-файла.

Код, который у меня сейчас есть:

def bulk_download
  require('zip')
  ::Zip::File.open("/tmp/mms.zip", Zip::File::CREATE) do |zipfile|
    Attachment.all.each do |attachment|
      image_file = Tempfile.new("#{attachment.created_at.in_time_zone}.png")
      image_file.write(attachment.image_string)
      zipfile.add("#{attachment.created_at.in_time_zone}.png", image_file.path)
    end
  end
  send_file "/tmp/mms.zip", type: 'application/zip', disposition: 'attachment', filename: "my_archive.zip"
  respond_to do |format |
    format.all { head :ok, content_type: "text/html" }
  end
end

Но в загруженном zip-файле нет файлов, а его размер составляет 0 байт.Заранее спасибо.

1 Ответ

0 голосов
/ 05 февраля 2019

Вам необходимо закрыть и отсоединить zip-файл следующим образом:

require('zip')

class SomeController < ApplicationController
  # ...

  def bulk_download
    filename = 'my_archive.zip'
    temp_file = Tempfile.new(filename)

    begin
      Zip::OutputStream.open(temp_file) { |zos| }

      Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip|
        Attachment.all.each do |attachment|
          image_file = Tempfile.new("#{attachment.created_at.in_time_zone}.png")
          image_file.write(attachment.image_string)
          zipfile.add("#{attachment.created_at.in_time_zone}.png", image_file.path)
        end
      end

      zip_data = File.read(temp_file.path)
      send_data(zip_data, type: 'application/zip', disposition: 'attachment', filename: filename)
    ensure # important steps below
      temp_file.close
      temp_file.unlink
    end
  end
end

Вот хорошее сообщение в блоге, которое я использовал в качестве источника для этого кода: https://thinkingeek.com/2013/11/15/create-temporary-zip-file-send-response-rails/

Кроме того, рекомендуется хранить все требования к библиотеке в верхней части файла (например, require('zip')).

...