The ultimate goal here is to create a stream so that I can attach the xlsx doc generated from the axlsx package object. I'm able to serialize the package and it writes to the file system just fine. I don't really have the need or want to write the document the file system.
Here is the error I get when I call to_stream:
NoMethodError: undefined method `reopen' for "streamed":String Did
you mean? prepend
What am I doing wrong here?
Axlsx::Package.new do |p|
p.workbook do |wb|
wb.add_worksheet(name: 'Time Cards') do |ws|
title_style = ws.styles.add_style(sz: 24)
ws.add_row ["Week #{week}, #{year} Time Cards", '', ''], style: [title_style], height: 30
end
end
p.to_stream
end
Ruby v 2.4.0
Rails v5.0.2
For future visitors of this old question:
Check versions of axlsx and rubyzip in your Gemfile. For me the issue was that rubyzip was of version 1.2. Combination that works for me today (07.08.2017) is:
axlsx (2.1.0.pre) and rubyzip (~> 1.1.7)
Related
I have generated many PDF files in memory and I want to compress them into one zip file before sending it as a email attachment. I have looked at Rubyzip and it does not allows me to create a zip file without saving it to disk (maybe I am wrong).
Is there any way I can compress those file without creating a temp file?
I had a similar problem which I solved using the rubyzip gem and the stringio object.
It turns out that rubyzip provides a method that returns a stringio object: ZipOutputStream.write_buffer.
You can create the zip file structure as you like using put_next_entry and write and once you are finished you can rewind the stringio and read the binary data using sysread.
See the following simple example (works for rubyzip 0.9.X)
require 'zip/zip'
stringio = Zip::OutputStream.write_buffer do |zio|
zio.put_next_entry("test.txt")
zio.write "Hello world!"
end
stringio.rewind
binary_data = stringio.sysread
Tested on jruby 1.6.5.1 (ruby-1.9.2-p136) (2011-12-27 1bf37c2) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [Windows Server 2008-amd64-java])
The following example works for rubyzip >= 1.0.0
require 'rubygems'
require 'zip'
stringio = Zip::OutputStream.write_buffer do |zio|
zio.put_next_entry("test.txt")
zio.write "Hello world!"
end
binary_data = stringio.string
Tested on jruby 1.7.22 (1.9.3p551) 2015-08-20 c28f492 on OpenJDK 64-Bit Server VM 1.7.0_79-b14 +jit [linux-amd64] and rubyzip gem 1.1.7
Ruby comes with a very convenient StringIO library - this can be used for using a String as output IO object or faking reading a file backed by a String.
The challenge here is that RubyZip does not support directly taking an IO object when creating a Zip::ZipOutputStream, but if you look at the implementation of the initialize, and depending on your willingness to experiment, you may be able to extend the class and allow it to take either an IO object or a file name in the constructor.
There are two RubyZip libraries that I was able to find.
Chilkat's Ruby Zip Library
rubyzip on Sourceforge
Chilkat's library definitely allows one to create a zip file in memory instead of writing it to disk automatically as seen in these links: Zip to Memory, Zip from in memory data
The one on SourceForge, on the other hand, may provide an option of zipping a file in memory but I'm not entirely certain since I'm very new to ruby. The SourceForge rubyzip is based on java.util.zip which has led to it having a class called ZipOutputStream. I don't know how good the rubyzip implementation is, but with java.util.zip implementation the OutputStream can be set to ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream....
If that holds true for the rubyzip implementation then it should be a matter of using ZipOutputStream to pass in a ByteArrayOutputStream of sorts which would result in it being output to memory.
If it doesn't exist in rubyzip, then I'm sure you could always write your own implementation and submit it for inclusion in rubyzip seeing as it is opensource.
If you're on Linux, and depending upon how much RAM you have, and how large your files are, you could always use tmpfs (shared memory). Then, the rubyzip disk-based methods will work. http://www.mjmwired.net/kernel/Documentation/filesystems/tmpfs.txt
The accepted answer works well but it didn't solve my problem. I didn't want to use the write_buffer method because it automatically closes the stream after the block closes. The code snippet below gives you more control over when the stream is created and closed.
require 'stringio'
require 'zip'
io = StringIO.new
zip_io = Zip::OutputStream.new(io, true) # 'true' indicates 'io' is a stream
zip_io.put_next_entry('test.txt')
zip_io.write('Hello world!')
# Read the data and close the streams
io.rewind
binary_data = io.read
zip_io.close_buffer
io.close
I am uploading a pdf file using paperclip to s3. I want to apply password protection on the fly to the uploaded pdf file.
I tried to use the code given in question How to edit or write on existing PDF with Ruby?! to edit existing pdf file (the tmp file used by the paperclip) and try to apply password protection using
Prawn::Document.generate("tmp/abc.pdf",:template => params[:ebook].path) do encrypt_document(:user_password => 'foo', :owner_password => 'bar',
:permissions => { :print_document => false,
:modify_contents => false,
:copy_contents => false,
:modify_annotations => false } end
Is the template support still exist in prawn or it had been deprecated as i didn't find anything regarding template in the prawn manual! ?
Is there any other way or any other gem to do so ?
Thanks.
template was removed in version 0.13.0 because it was too buggy :
Support for templates was dropped in Prawn 0.13.0, disabled by default in 0.14.0, and extracted in 0.15.0.
This gem includes the extracted templates code, which is completely unsupported, but provides the old functionality that was in Prawn 0.12.0 for years.
source : https://github.com/prawnpdf/prawn-templates
As he said, you can try to add the library to your current Prawn installation.
Otherwise you can use pdftk with Open3 module (http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/) :
require 'open3'
file_name = 'hello_world_1.pdf' # input
file_name_output = 'hello_world_2.pdf' # output
usr = 'foo'
pwd = 'bar'
pdftek = './pdftk.exe' # tested on windows
Open3.popen3("#{pdftek} #{file_name} output #{file_name_output} owner_pw #{pwd} user_pw #{usr}") do |stdin,stdout,stderr|
# ...
end
There is also a wrapper for ruby but I haven't test it yet : https://github.com/tcocca/active_pdftk
When I open a file in xlsx format, using empact/roo gem, this line of code:
data = Roo::Spreadsheet.open("/Users/asd/Desktop/in_xlsx.xlsx", extensions: :xlsx)
or this line
data = Roo::Excelx.new("/Users/asd/Desktop/in_xlsx.xlsx")
works perfect! (at least this is what I think)
data is now a Roo::Excelx object with the columns and rows filled correctly.
But whenever I try to use a method like data.first_row or data.cell(1,1), I get this
NameError: uninitialized constant Spreadsheet::Link
from /Users/asd/.rvm/gems/ruby-2.0.0-p353#ch/gems/roo-1.13.2/lib/roo/excelx.rb:379:in `set_cell_values'
Additional info:
MacOS 10.9.1
Rails 4.0.2
Ruby 2.0.0-p353
Roo (1.13.2)
Any help is really appreciated!
Try this :
require 'rubygems'
require 'roo'
For more information http://roo.rubyforge.org/
I am implementing in Ruby and i am running a project which reads a CSV file to add users.
but when i pick my file it just gives always the same error:
FasterCSV::MalformedCSVError in User importController#match
Illegal quoting on line 1.
my CSV file just exists of :
"RubenPersoon1","test","Bauwens","Ruben","rub#gmail.com",0
anyone who knows what can be wrong?
Try to upgrade your FasterCSV gem version. With the latest version it works:
FasterCSV.parse_line '"RubenPersoon1","test","Bauwens","Ruben","rub#gmail.com",0'
=> ["RubenPersoon1", "test", "Bauwens", "Ruben", "rub#gmail.com", "0"]
ruby-1.8.7-p352 :005 > FasterCSV.parse '"RubenPersoon1","test","Bauwens","Ruben","rub#gmail.com",0'
=> [["RubenPersoon1", "test", "Bauwens", "Ruben", "rub#gmail.com", "0"]]
Also, keep in mind that if you are on Ruby 1.9.2, FasterCSV is already included. Just require 'csv' and use the CSV class.
I have a rails application that is being upgraded from Rails 2.3.5 to Rails 3. It uses attachment_fu for file uploads. We're trying to do this conversion without making DB changes, so I'd like to avoid changing to paperclip or carrierwave at this time.
Has anyone succeeded in using attachment_fu with Rails 3 and Ruby 1.9.2? We're using the most recent version of attachment_fu that claims to be ok for rails 3 and ruby 1.9.2, but getting 'TypeError (can't convert nil into Integer):' on any forms that include a file upload.
All the answers to previous questions seem to be 'just switch to paperclip or carrierwave' as in:
Attachment_fu or Paperclip for Rails3
or
TypeError (can't convert nil into Integer):
Thanks!
I made the following changes and it worked
attachment_fu.rb
def temp_path
p = temp_paths.first
if p.is_a?(ActionDispatch::Http::UploadedFile) # Rails 3.0.3 compatability fix
p.tempfile.path
else
p.respond_to?(:path) ? p.path : p.to_s
end
end
I also changed returning filename.strip do |name| to filename.strip.tap do |name|
init.rb
def make_tmpname(basename, n)
ext = nil
n ||= 0
sprintf("%s%d-%d%s", basename.to_s.gsub(/\.\w+$/) { |s| ext = s; '' }, $$, n, ext)
end
I made a fork on github with this changes
https://github.com/debprado/attachment_fu
attachment_fu patches Tempfile.make_tmpname in attachment_fu/init.rb, and it doesn't work in 1.9.2: sprintf("%d",nil) fails, and in 1.8.7 the result of this expression is "0".
The fix is to insert a line in init.rb from:
sprintf('%s%d-%d%s', File::basename(basename, ext), $$, n, ext)
to
n ||= 0
sprintf('%s%d-%d%s', File::basename(basename, ext), $$, n, ext)
You can find some of the discussion here https://github.com/technoweenie/attachment_fu/issues/25
Cheers!
Try my gemified version that supports Rails 3.2:
https://rubygems.org/gems/pothoven-attachment_fu