使用 RubyZip 生成文件并下载为 zip
Generate files and download as zip using RubyZip
对于我在 Rails 项目(Rails 版本 5.1.2)上的 Ruby,我正在生成图像文件 (png) 并使用 [=26 将它们下载为 zip 文件=]邮编gem。
图像文件未存储在任何目录中。我有一个名为附件的模型。每个附件都有一个属性 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字节。
提前致谢。
您应该像这样关闭并取消链接 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
这是一个很好的博客 post,我将其用作此代码的来源:https://thinkingeek.com/2013/11/15/create-temporary-zip-file-send-response-rails/
此外,最好将所有库要求都放在文件的顶部(即 require('zip')
)。
接受的解决方案确实是正确的。但是,我将扩展已提供的解决方案以使其与 ActiveStorage
附件一起使用。
在使用公认的解决方案时,我发现 image_string
方法不适用于 ActiveStorage
附件并抛出这样的错误
NoMethodError - undefined method `image_string' for #<ActiveStorage::Attached::One:0x00007f78cc686298>
假设我们有一个名为 Product
的 rails 模型和一个名为 attachment
的 ActiveStorage 属性
class Product < ApplicationRecord
has_one_attached :attachment
end
为了使它适用于 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
对我有用(我需要加载基于 Carrierwave 的 MyModel 文档):
require 'zip'
require 'open-uri'
class TestsController < ApplicationController
def index
filename = 'test.zip'
temp_file = ::Tempfile.new(filename)
my_model_document = ::MyModel.last
my_model_document_name = ::File.basename(my_model_document.document.path)
begin
::Zip::OutputStream.open(temp_file) { |zos| }
::Zip::File.open(temp_file.path, ::Zip::File::CREATE) do |zipfile|
dr_temp_file = Tempfile.new(my_model_document_name)
dr_temp_file.write(open(my_model_document.document.url).read.force_encoding("UTF-8"))
zipfile.add(my_model_document_name, dr_temp_file.path)
end
zip_data = File.read(temp_file.path)
send_data(zip_data, type: 'application/zip', disposition: 'attachment', filename: filename)
ensure
temp_file.close
temp_file.unlink
end
end
end
对于我在 Rails 项目(Rails 版本 5.1.2)上的 Ruby,我正在生成图像文件 (png) 并使用 [=26 将它们下载为 zip 文件=]邮编gem。
图像文件未存储在任何目录中。我有一个名为附件的模型。每个附件都有一个属性 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字节。 提前致谢。
您应该像这样关闭并取消链接 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
这是一个很好的博客 post,我将其用作此代码的来源:https://thinkingeek.com/2013/11/15/create-temporary-zip-file-send-response-rails/
此外,最好将所有库要求都放在文件的顶部(即 require('zip')
)。
接受的解决方案确实是正确的。但是,我将扩展已提供的解决方案以使其与 ActiveStorage
附件一起使用。
在使用公认的解决方案时,我发现 image_string
方法不适用于 ActiveStorage
附件并抛出这样的错误
NoMethodError - undefined method `image_string' for #<ActiveStorage::Attached::One:0x00007f78cc686298>
假设我们有一个名为 Product
的 rails 模型和一个名为 attachment
class Product < ApplicationRecord
has_one_attached :attachment
end
为了使它适用于 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
对我有用(我需要加载基于 Carrierwave 的 MyModel 文档):
require 'zip'
require 'open-uri'
class TestsController < ApplicationController
def index
filename = 'test.zip'
temp_file = ::Tempfile.new(filename)
my_model_document = ::MyModel.last
my_model_document_name = ::File.basename(my_model_document.document.path)
begin
::Zip::OutputStream.open(temp_file) { |zos| }
::Zip::File.open(temp_file.path, ::Zip::File::CREATE) do |zipfile|
dr_temp_file = Tempfile.new(my_model_document_name)
dr_temp_file.write(open(my_model_document.document.url).read.force_encoding("UTF-8"))
zipfile.add(my_model_document_name, dr_temp_file.path)
end
zip_data = File.read(temp_file.path)
send_data(zip_data, type: 'application/zip', disposition: 'attachment', filename: filename)
ensure
temp_file.close
temp_file.unlink
end
end
end