[Ruby]IO.Read not reading the whole file - ruby-on-rails

I want to download a zip file containing some images via a rails method. The problem is that when I try to read thoses files, I'm not getting the entire file. Of course, that's pretty much annoying to display the image.
Here is my code :
def download_zip(image_list)
if !image_list.blank?
file_name = "pictures.zip"
t = Tempfile.new("lolbite11")
Zip::OutputStream.open(t.path) do |z|
image_list.each do |img|
title = img.name
title += ".jpg" unless title.end_with?(".jpg")
z.put_next_entry(title)
z.print IO.read(Rails.root.join('public', img.path)) <- Here is the problem ?
end
end
send_file t.path, :type => 'application/zip',
:disposition => 'attachment',
:filename => file_name
t.close
end
end
After I've download the zip and extract it. I open my images with a text editor and sadly see that I've not the whole image... I tried to output the 'IO.read' and it's only displaying what is in my final file.

I finally found an other way to solve my problem with File.copy_stream().
But if someone knows why this doesn't work, feel free to explain to me.

Related

Rails download http response/displayed site

Instead of displaying the xml file rendered by the index.api.rsb file in my browser, i want to download it. To me this sounds very simple, but I cant find a solution.
I tried the following in the controller-method:
def split
if params[:export] == "yes"
send_file *here comes the path to xml view*, :filename => "filename", :type => :xml
end
respond_to ...
end
The result is a MissingFile exception...
Thanks in advance
Note that :disposition for send_file defaults to 'attachment', so that shouldn't be a problem.
If you have a MissingFile exception, that means the path is incorrect. send_file expects the path to an actual file, not a view that needs to be rendered.
For your case, render_to_string might be what you need. Refer to this related question. It renders the view and returns a string instead of setting the response body.
def split
if params[:export] == "yes"
send_data(render_to_string path_to_view, filename: "object.xml", type: :xml)
end
end
To force it to download it, add :disposition => attachment to your send_file method.
Source: Force a link to download an MP3 rather than play it?

When using redirect_to files on s3. How to either display an image or download a file

In Rails 3 AttachmentsController, I have the following:
def show
attachment = Attachment.find_by_id(params[:id])
redirect_to(attachment.authenticated_url())
end
Where authenticated_url is simply a URL to S3 to access the file.
The problem is that the file is always downloaded by the browser. What I would like to have happen is if the file is an image/pdf, something the browser can render, show the file in the browser and only download non-browser friendly files.
Have you seen this before? Any ideas on where to start?
Thanks
send_file can be used for remote url as well
file = open("http://cdn2.example.com/somefile.pdf")
send_file(file, :filename => "example.pdf", :type => "application/pdf" , :disposition => "attachment")
Here example.pdf will be downloaded. If you want open pdf in browser itself use this
file = open("http://cdn2.example.com/somefile.pdf")
send_file(file, :filename => "example.pdf", :type => "application/pdf" , :disposition => "inline")
redirect_to #attachment.url
I'm using Paperclip as well, and this display pictures inside the browser. Do you have to do something different than this?
I think you'll want to look into the rails send_file method.
1) http://apidock.com/rails/ActionController/DataStreaming/send_file
The :disposition option lets you decide whether a file will be downloaded or displayed inline. I used this in my rails app to let users download mp3 files.
Hope this helps.

pdftk, tempfile and rails

Ok, I've tried all kinds of stuff and I'm not entirely sure this will work. The pdfs I need to merge are on the server and the links to them are hardcoded. pdftk works locally in my terminal, but not with these remote links. So I'm unsure if this will work once I get it up to production.
Basically, I'm trying to write a method that will retrieve a selected group of pdfs and merge them into one pdf for the user to download.
But I'm having a hard time deciphering how to utilize tempfiles and running terminal commands through the rails app.
Here is the method:
def create
#routes = TransitRoute.find(params[:selected_routes])
#selected_routes = #routes.collect {|x| x.new_pdf_link + " "}
Tempfile.open('prefix', "#{Rails.root}/tmp") do |f|
f.print("pdftk #{#selected_routes} cat output temporary.pdf")
f.flush
f.read
end
respond_to do |format|
format.html
end
end
I have a couple questions:
My tempfile has the correct command line written to it:
pdftk 1.pdf 2.pdf cat output new.pdf
How do I get this line run so that the new.pdf is created?
Am I supposed to replace the tempfile with the new pdf, or write the new pdf to it or just make the new pdf in it's own location? If the latter, how do I get it to be temporary?
How do I get a link to the new pdf so users can download it?
Some of this may be basic stuff, but I've never had to mess with tempfiles of making pdfs dynamically like this.
Oh yeah, and this app is also in Rails 2.3
Thanks for any help.
Ok, I have it working. Here's the new code incase someone has advice for improvement or has the same question:
def create
file = Tempfile.new('temp_route_pdf', "#{Rails.root}/tmp/")
#routes = TransitRoute.find(params[:selected_routes])
selected_routes = #routes.collect {|x| x.new_pdf_link + " "}
route_names = #routes.collect {|x| x.short_name + "_"}
#generated_pdf_file = "#{route_names}routes.pdf"
`pdftk #{selected_routes}cat output #{file.path}`
raise Exception unless $?.success?
send_file( "#{file.path}",
:type => "application/pdf",
:filename => "#{#generated_pdf_file}",
:disposition => 'inline')
end

CSV.open and send_data in rails....?

I may end up figuring this out later, but i thought I'd try.
Can someone help combine send_data and CSV.open
According to the docs, you can CSV.open filename, mode(whatever that is) and basically a file will save to your current path. However, if you want to send that file to a user through his broswer, as most of us who give the option of CSV files to download, do,do... then can we combine the CSV.open with send_data?
thoughts?
examples welcome if you do something like this too.
I don't think you want to combine those two things.
CSV.open will save the data to a file, which you would need to read back in in order to send it through send_data.
But you can do something like:
csv = []
csv << ["titles", "for", "csv"]
csv << ["data", "for", "csv"]
send_data(csv.collect{|s| s.join(",")}.join("\n"),
:type => 'text/csv; charset=utf-8; header=present',
:filename => "mytitle.csv")
Which should prompt the user to download the csv file.

Saving XML files with Rails

im working on a Rails project that should create XMl files, or to be more specific
use existing XMl templates and put content from the database in it.
So i dont need to create the xml structure, basically just rendering a template with content.
What would be the smartest way to do that?
So far i have a file.xml.erb in my layout folder
and i have a custom route "/renderXML" that does
def renderXML
#reading_question = ReadingQuestion.find(params[:id])
render :file => 'layouts/question.xml'
end
This works, but i also want to save the file, not only show it (actually viewing it is not really needed).
For saving i found this
File.open('fixed.xml','w'){|f| f.write builder.to_xml}
How do i access the rendered file and save it with some method like above?
Perhaps something like:
s = render_to_string :file => 'layouts/question.xml'
File.open('fixed.xml','w'){|f| f.write s}
render :text => s
Another approach :
send_data fixed, :type => 'text/xml; charset=UTF-8;', :disposition =>
"attachment; filename=fixed.xml"

Resources