caxlsx / caxlsx_rails

A Rails plugin to provide templates for the axlsx gem
MIT License
744 stars 84 forks source link

Generating xlsx from model #53

Closed agustaf9 closed 8 years ago

agustaf9 commented 8 years ago

I am trying to get the spreadsheet after it is generated by axlsx into my model so I can zip it up with some other files. How would I go about doing this?

Edit: I know how to zip, I am just wondering how to generate the spreadsheet from my model.

straydogstudio commented 8 years ago

You can do something like this:

def some_action
   compressed_filestream = Zip::ZipOutputStream.write_buffer do |zos|
      content = render_to_string xlsx: 'export', filename: filename, layout: false
      zos.put_next_entry(filename)
      zos.print content
      # add other files
   end
   compressed_filestream.rewind
   send_data compressed_filestream.read, filename: 'export.zip', type: 'application/zip'
end

I am assuming you are wanting to return the zip to a request. Let me know if you had something else in mind.

layout: false may not be necessary; in some circumstances Rails tries to add a layout to axlsx files.

agustaf9 commented 8 years ago

I do want to return a zip to a request but it is a zip that includes many different files. I have a method in my model that gets many local files and zips them into a single folder. I am wondering if there is a way to add the file that axlsx generates to that folder. Basically what I am wondering is if there is a way I can call axlsx from the model?

straydogstudio commented 8 years ago

You can use the same render_to_string and dump it into a file in your directory:

content = render_to_string xlsx: 'export', filename: filename, layout: false
File.open('/tmp/axlsx_temp.xlsx', 'w') {|f| f.write(content) }

If you are calling this inside a model, then you may have a bit of an issue getting to render to string. There will likely be posts on the internet about that. I've not done it myself. You may have to do something like this.

It is possible to render a template directly without the overhead of ActionView. See this test.

agustaf9 commented 8 years ago

I am going to close it because it works, but... can someone tell me if there is something really wrong with what I am doing here? (Note: model is the name of one of my models)

def download
  tempfile = Tempfile.new
  children = self.children_with_forms
   Zip::OutputStream.open(tempfile) do |stream|
    children.each do |child|
      directory = "#{child.wide_reference[0,3]}/"
      if child.model_name == "Position"
        av = ActionView::Base.new(ActionController::Base.view_paths, {position: child, model: child.model})
        stream.put_next_entry("#{directory}#{child.volume} #{child.title} TOC.xlsx")
        stream.print av.render template: 'pages/toc.xlsx.axlsx'
      end
      stream.put_next_entry("#{directory}#{child.wide_reference} #{child.title.truncate(15, omission:'')} (#{child.short_name}).docx")
      stream.print IO.read(child.download_form.path)
    end
    stream.put_next_entry("excel file.xlsx")
    av = ActionView::Base.new(ActionController::Base.view_paths, {model: self})
    stream.print av.render template: 'pages/excel_file.xlsx.axlsx'
  end
  tempfile
end

Thank you for your help! And thank you for this wonderful gem!

straydogstudio commented 8 years ago

@agustaf9 Glad that worked! I don't see anything wrong in particular. As long as things are working I think you are ok.

You are welcome for the help and gem.