What is the best way to send xlsx file via API to frontend and how?
I'm using axlsx_rails gem for generating report with xlsx template.
Options I found are: json,base64,html.
Generate .xlsx file and respond filename as json/html
Rendering xlsx now:
render xlsx: 'status_report', template: 'api/v1/report/status_report.xlsx.axlsx'
I know this is a old question but I choosed the base64 option.
Axlsx::Package.new do |obj|
obj.workbook.add_worksheet(name: "Sheet Name") do |sheet|
# Sheet structure and rows...
end
send_data Base64.encode64(obj.to_stream.read), type: "application/xlsx", filename: 'filename.xlsx'
end
Just use the send_data rails method (send_data)
you can use send_file like this:
def export
Axlsx::Package.new do |obj|
obj.workbook.add_worksheet(name: 'worksheet name') do |sheet|
# Sheet structure and rows...
end
obj.serialize('filename.xlsx')
send_file File.open('filename.xlsx')
end
end
do not forget to add rubyzip, axlsx, axlsx_rails gems to your gemfile.
You should change in application_controller ActionController::API to ActionController::Base
Related
I'm setting up an account profil system and i want to support an avatar with active_storage in my rails app.
I'm expecting to see my avatar but instead i've got thisbroken_pics
If i open the picture in an other tabs he send me this app/controllers/active_storage/disk_controller.rb line 10-17:
def show
if key = decode_verified_key
serve_file disk_service.path_for(key[:key]), content_type: key[:content_type], disposition: key[:disposition]
else
head :not_found
end
end
the problem come from this line or above serve_file disk_service.path_for(key[:key]), content_type: key[:content_type], disposition: key[:disposition]
We just had this same issue. Turns out the implementation of ActiveStorage::DiskController#show changed from Rails 5.2.1 to Rails 5.2.2. See 5.2.1 vs 5.2.2
The active_storage-postgresql gem relied on the behaviour of Rails 5.2.1. It looks like there is a PR that has just been merged to fix this, so I expect there will soon be a new release of the gem to restore Rails compatibility. Keep an eye on https://rubygems.org/gems/active_storage-postgresql .
As a temporary fix, we added a controller action like so to download the blobs via send_file.
def download_file
attachment = ActiveStorage::Attachment.find(params[:id])
file = attachment.blob
data = file.download
send_data(data, type: file.content_type, filename: file.filename, disposition: "inline")
end
# then call like
download_file_path(model.file.id)
#user10981734's answer worked for me. I was actually able to boil it down to something more concise:
file = ActiveStorage::Attachment.find(params[:id]).blob
send_data(
file.download,
type: file.content_type,
filename: File.basename(file.filename.to_s)
)
I am looking for a way to create multiple csv files and download them as one zip archive within one request in my rails application.
To build the archive I use rubyzip gem - to download it just the rails built-in function send_data. The problem I have is that rubyzip's add-function requires a pathname to load files from. But there is no path as my csv files are created within the same request.
Some Code:
# controller action to download zip
def download_zip
zip = #company.download_all
send_data zip, filename: "abc.zip", type: 'application/zip'
end
# method to create zip
def download_all
Zip::File.open('def.zip', Zip::File::CREATE) do |zipfile|
self.users.each do |user|
#some magic to combine zipfile.add() and user.to_csv
end
end
end
# method to create csv
def to_csv
CSV.generate do |csv|
#build awesome csv
end
end
Is there a way to save my csv files temporarely at some directory, that I can pass a pathname to zipfile.add()?
Nice weekend everybody and happy coding!
You could either write your CSV output into a temporary file and call zipfile.add() on that, but there is a cleaner solution:
zipfile.get_output_stream("#{user.name}.csv") { |f| f.puts(user.to_csv) }
See http://rdoc.info/github/rubyzip/rubyzip/master/Zip/File#get_output_stream-instance_method for more details on get_output_stream - you can also pass additional parameters to specify attributes for the file to be created.
get_output_stream doesn't work for me. However, the updated method Zip::OutputStream.write_buffer helps
https://gist.github.com/aquajach/7fde54aa9bc1ac03740feb154e53eb7d
The example adds password protection to the file as well.
How to generate compressed files on request.
I have this controller
def create
send_data generate_tgz("#{RAILS_ROOT}/tmp/example.txt"), :filename => 'export.tgz'
end
But it gives me a method not found on generate_tgz.
Is it a plugin or gem? Do I need to require anything? Can I generate a zip file instead?
Edit:
def generate_tgz(file)
system("tar -czf #{RAILS_ROOT}/tmp/export-result #{RAILS_ROOT}/tmp/export")
content = File.read("#{RAILS_ROOT}/tmp/export-result")
#ActiveSupport::Gzip.compress(content)
end
This creates a tgz, but when I decompress it I get app/c3ec2057-7d3a-40d9-9a9d-d5c3fe3ffd6f/home/tmp/export/and_the_files
I would like it to just be: export/the_files
The method doesn't exist. You can easily create it using ActiveSupport::Gzip.
def generate_tgz(file)
content = File.read(file)
ActiveSupport::Gzip.compress(content)
end
I want to be able to upload an Excel file that contains contact information. I then went to be able to parse it and create records for my Contact model.
My application is a Rails application.
I am using the paperclip gem on heroku, I've been able to parse vim cards into the Contact model, and am looking for something similar, but will go through all lines of the Excel file.
Gems that simplify the task and sample code to parse would be helpful!
Spreadsheet is the best Excel parser that I have found so far. It offers quite a lot of functionality.
You say you use Paperclip for attachments which is good. However, if you store the attachments in S3 (which I assume since you use Heroku) the syntax for passing the file to spreadsheet is a little different but not difficult.
Here is an example of the pure syntax that can be used and not placed in any classes or modules since I don't know how you intend to start the parsing of contacts.
# load the gem
require 'spreadsheet'
# In this example the model MyFile has_attached_file :attachment
#workbook = Spreadsheet.open(MyFile.first.attachment.to_file)
# Get the first worksheet in the Excel file
#worksheet = #workbook.worksheet(0)
# It can be a little tricky looping through the rows since the variable
# #worksheet.rows often seem to be empty, but this will work:
0.upto #worksheet.last_row_index do |index|
# .row(index) will return the row which is a subclass of Array
row = #worksheet.row(index)
#contact = Contact.new
#row[0] is the first cell in the current row, row[1] is the second cell, etc...
#contact.first_name = row[0]
#contact.last_name = row[1]
#contact.save
end
I had a similar requirement in one of my Rails 2.1.0 application. I solved it in the following manner:
In the 'lib' folder I wrote a module like this:
require 'spreadsheet'
module DataReader
def read_bata(path_to_file)
begin
sheet = book.worksheet 0
sheet.each 2 do |row|
unless row[0].blank?
# Create model and save it to DB
...
end
end
rescue Exception => e
puts e
end
end
end
Had a model Upload:
class Upload < AR::Base
has_attached_file :doc,
:url => "datafiles/:id",
:path => ":rails_root/uploads/:id/:style/:basename.:extension"
# validations, if any
end
Generated an UploadsController which would handle the file upload and save it to appropriate location. I used Paperclip for file upload.
class UploadsController < AC
include DataReader
def new
#upload = Upload.new
end
def create
#upload = Upload.new(params[:upload])
#upload.save
file_path = "uploads/#{#upload.id}/original/#{#upload.doc_file_name}"
#upload.read = DataReader.read_data(file_path)
# respond_to block
end
end
Read about 'spreadsheet' library here and here. You can make appropriate improvements and make the technique work in Rails 3. Hope this helps.
I made a gem to achieve this easily. I called it Parxer and...
It's built on to of roo gem.
It allows you to parse xls, xlsx and csv files.
Has a DSL to handle:
Column mapping.
File, row, and column/cell validation.
Column/cell formatting.
I need to be able to render some views as PDFs from a Rails 3 project. I've never before used PDF generation techniques with ruby/rails, so I researched a few popular approaches such as Prawn and PDF::Writer, but all the examples and articles I found so far seem outdated and only applicable for rails 2.x. I haven't yet seen a working Rails3 example; tried myself installing prawn and the prawnto gems and reproducing the example described in this Railscasts episode, but I'm getting error of prawnto method not being recognized. I'm uncertain of whether this was an implementation error or just a sign of incompatibility, but seeing other people share on the web that prawn is no longer working for them in Rails3 I didn't bother tracing the code further.
Has anyone found a working reliable solution for pdf generation in Rails3? Could you possibly share it or point me to external resources and documentation?
Big thanks!
New answer to an old question, in case others stumble across this: WickedPDF (which uses wkhtmltopdf just like PDFkit) makes this a snap.
https://github.com/mileszs/wicked_pdf
Prawn does work with Rails 3. I have personally used it with no problems. You do have to get the latest versions of the gem and the prawnto plugin for rails.
PDFkit does have the advantage of using the Webkit rendering engine, so you get to use CSS to define your layouts, and you get matching web pages for free with Safari and Chrome. It has a slightly nicer learning curve than Prawn.
Have you seen PDFkit? I'm pretty sure that works with Rails 3, it is a piece of Rack middleware that can convert any HTML page to PDF that matches a route ending in .pdf
About prawn, here is a seamless integration for Rails 3 that seems to work just fine: https://github.com/Whoops/prawn-rails
You can use the Report gem, which generates PDF but also XLSX and CSV.
# a fake Manufacturer class - you probably have an ActiveRecord model
Manufacturer = Struct.new(:name, :gsa)
require 'report'
class ManufacturerReport < Report
table 'Manufacturers' do # you can have multiple tables, which translate into multiple sheets in XLSX
head do
row 'Manufacturer report'
end
body do
rows :manufacturers
column 'Name', :name
column 'GSA?', :gsa
end
end
# you would want this so that you can pass in an array
# attr_reader :manufacturers
# def initialize(manufacturers)
# #manufacturers = manufacturers
# end
def manufacturers
[
Manufacturer.new('Ford', true),
Manufacturer.new('Fischer', false),
Manufacturer.new('Tesla', nil),
]
end
end
When you call report.pdf.path, a PDF is generating in the tmp directory:
report = ManufacturerReport.new
puts report.pdf.path #=> /tmp/185051406_Report__Pdf.pdf
puts report.xlsx.path #=> /tmp/185050541_Report__Xlsx.xlsx
You can do it in your controller like:
#manufacturers = Manufacturer.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #manufacturers }
format.pdf do
report = ManufacturerReport.new(#manufacturers) # using the commented-out code
send_file report.pdf.path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'ManufacturersReport.pdf'
# tmp files are periodically cleaned up by the operating system, but if you want to be extra clean you can call
# report.cleanup
# but this may remove the tmp files before apache/nginx/etc. finishes delivering the file
end
end
End result:
PDF
XLSX
Note that the XLSX has an autofilter added for you automatically.