Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 使用RubyZip生成文件并作为zip下载_Ruby On Rails_File_Base64_Zipfile_Rubyzip - Fatal编程技术网

Ruby on rails 使用RubyZip生成文件并作为zip下载

Ruby on rails 使用RubyZip生成文件并作为zip下载,ruby-on-rails,file,base64,zipfile,rubyzip,Ruby On Rails,File,Base64,Zipfile,Rubyzip,对于我的RubyonRails项目(Rails版本5.1.2),我正在生成图像文件(png),并使用RubyZip gem将它们作为zipfile下载 图像文件不存储在任何目录中。我有一个模型叫附件。每个附件都有一个属性image_string,它是图像的base64字符串。您可以使用类似于image\u标记(src=“data:image/jpeg;base64,{attachment.image\u string}”,样式:“border radius:0;”)的标记来显示图像 对于多个图像

对于我的RubyonRails项目(Rails版本5.1.2),我正在生成图像文件(png),并使用RubyZip gem将它们作为zipfile下载

图像文件不存储在任何目录中。我有一个模型叫附件。每个附件都有一个属性image_string,它是图像的base64字符串。您可以使用类似于
image\u标记(src=“data:image/jpeg;base64,{attachment.image\u string}”,样式:“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
但下载的zipfile中没有文件,大小为0字节。
提前感谢。

您应该像这样关闭和取消链接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
require('zip'))
类SomeController
以下是我用作此代码源代码的一篇很好的博客文章:


此外,最好将所有库要求放在文件的顶部(即
require('zip')
)。

公认的解决方案确实是正确的。但是,我将扩展已经提供的解决方案,使其能够与
ActiveStorage
附件一起工作
在使用公认的解决方案时,我发现
image\u string
方法对
ActiveStorage
附件不起作用,并抛出如下错误

NoMethodError - undefined method `image_string' for #<ActiveStorage::Attached::One:0x00007f78cc686298>
为了使ActiveStorage附件能够正常工作,我们需要如下更新代码

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

  Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip|
    Product.all.each do |product|
      image_file = Tempfile.new("#{product.attachment.created_at.in_time_zone}.png")
      
    # image_file.write(product.attachment.image_string) #this does not work for ActiveStorage attachments
      
      # use this instead
      File.open(image_file.path, 'w', encoding: 'ASCII-8BIT') do |file|
        product.attachment.download do |chunk|
          file.write(chunk)
        end
      end

      zipfile.add("#{product.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

嘿@jl118,我的答案对你有用吗?
begin
  Zip::OutputStream.open(temp_file) { |zos| }

  Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip|
    Product.all.each do |product|
      image_file = Tempfile.new("#{product.attachment.created_at.in_time_zone}.png")
      
    # image_file.write(product.attachment.image_string) #this does not work for ActiveStorage attachments
      
      # use this instead
      File.open(image_file.path, 'w', encoding: 'ASCII-8BIT') do |file|
        product.attachment.download do |chunk|
          file.write(chunk)
        end
      end

      zipfile.add("#{product.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