I have a Rails application where I am storing a file on S3 using Fog/Carrierwave. When I go to download the file, I do not get the expected results. My code is the following:
v_file_name = "https://s3.amazonaws.com/{bucket}/{file}.pdf"
data = open(URI.parse(URI.encode(v_file_name)))
send_data data, :type => 'application/pdf', :disposition => 'attachment', :filename => "{filename}.pdf"
I expect to get the download file dialog, but I get redirected in the browser to a page that begins with:
%PDF-1.3 %���� 1 0 obj << /Creator /Producer >> endobj 2 0 obj....
And ending in:
..... << /Size 10 /Root 2 0 R /Info 1 0 R >> startxref 25361 %%EOF
This code had previously been working, but has suddenly stopped working.
Any help would be greatly appreciated!
Found the error. Problem was that I had implemented Turbolinks mid-project. Apparently Turbolinks breaks send_file & send_data in Rails. You can disable Turbolinks by adding "data-turbolinks='false'" to the link. This fixed it!
Related
I'm trying to download a zip file, sent from a rails 4 application to the front-end.
The zip file construction is working correctly, I can unzip the file and get the content
filename = "cvs_job_#{params[:job_id]}.zip"
archive_path ="#{Rails.root}/tmp/#{filename}"
File.delete(archive_path) if File.exists?(archive_path)
Zip::File.open(archive_path, Zip::File::CREATE) do |zipfile|
params[:user_ids].each do |user_id|
user = User.find(user_id)
zipfile.add("#{user.last_name}_#{user.first_name}.pdf", user.cv_file.path) unless user.cv_file.nil?
end
end
send_file("#{Rails.root}/tmp/#{filename}", :type => 'application/zip', :disposition => 'attachment')
but how am I supposed to handle the response back in the promise?
$http(req).success(function(success){
console.log(success)
})
I saw the zip file in the chrome console, such as :
"...8f�~��/g6�I�-v��=� ..."
I have tried many solutions but none are working.
I thought that I would be able to send the file and download from my front.
I have wkhtmltopdf binaries in my bin folder and my initializer is as follows:
PDFKit.configure do |config|
# if ["development"].include?(Rails.env)
if ENV["TRIPCIPE_ENV"] == "local"
config.wkhtmltopdf = Rails.root.join('bin', 'wkhtmltopdf').to_s
else
config.wkhtmltopdf = Rails.root.join('bin', 'wkhtmltopdf-amd64').to_s
end
end
my controller code looks like this
html = render_to_string(:action => "pdf", :layout => false)
kit = PDFKit.new(html)
send_data(kit.to_pdf, :filename => 'report.pdf', :type => 'application/pdf', :disposition => 'inline')
And it works fine locally but when I deploy on heroku I just get an empty 1 page pdf file.
Any ideas or help would be appreciated, thanks.
I also noticed in my logs it says this:
Unable to load library icui18n "Cannot load library icui18n: (icui18n: cannot open shared object file: No such file or directory)"
Anyone seen this before?
UPDATE
So i removed the initializer code and added the gem 'wkhtmltopdf-heroku', which makes the error go away but it's still returning a blank page.
I am trying to export data from a rails app and have the user download a CSV file when they hit a certain controller#action.
I found this article and used the sample code exactly.
http://oldwiki.rubyonrails.org/rails/pages/HowtoExportDataAsCSV
I do, in fact, get a CSV file, but within it, there is only one line of output:
#<Proc:0x00000001032c6808#/PATH_CRAP/app/controllers/reports_controller.rb:35>
Here are lines 35, 36 and 37 from the file in question.
render :text => Proc.new { |response, output|
csv = FasterCSV.new(output, :row_sep => "\r\n")
yield csv
I am using Rails 3.0.5 and added the following to my Gemfile:
gem 'fastercsv'
What gives?
render :text => proc {...} does not work in Rails 3. For the replacement, see this question.
I feel like this will end in a facepalm moment but I've been banging on my head on it for too long.
I have a Rails seed.rb file that gets all the files from a specific directory creating a new object for each file and saving the file via Paperclip:
Dir["./**/*.jpg"].each do |f|
...
p = Picture.new
File.open(f, 'r') { |photo_file| p.photo = photo_file }
p.save!
....
end
where photo is the Paperclip-assigned attribute (picture.rb):
has_attached_file :photo,
:styles => { :medium => "500x500>", :thumb => "100x100#" },
:processors => [:rotator]
My problem is after some number of files (some times 50, some times 2) the script exits with the following error:
No such file or directory - /var/folders/oD/oDq1WD11EEaXmfi8VfNvfE+++TM/-Tmp-/stream,22423,0,22423,0
/Users/patgeorge/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/fileutils.rb:1407:in `stat'
/Users/patgeorge/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/fileutils.rb:1407:in `block in fu_each_src_dest'
/Users/patgeorge/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/fileutils.rb:1423:in `fu_each_src_dest0'
/Users/patgeorge/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/fileutils.rb:1405:in `fu_each_src_dest'
/Users/patgeorge/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/fileutils.rb:504:in `mv'
/Users/patgeorge/.rvm/gems/ruby-1.9.2-head#rails3/bundler/gems/paperclip-61f74de14812cabc026967a2b2c3ca8cbd2eed69-master/lib/paperclip/storage.rb:42:in `block in flush_writes'
I thought maybe I wasn't closing the file but according to the Ruby IO docs using the block from of open will close the file.
Obviously I don't see myself having to run this often so it's not a huge problem. It's just frustrating and confusing.
I'm running Ruby 1.9.2 r28142, Rails 3.0.0.beta4, and Paperclip 2.3.3.
Additional:
Attempting Winfield's suggestion my code block now looks like this:
Dir["./**/*.jpg"].each do |f|
...
File.open(f, 'r') do |photo_file|
p = Picture.new
p.photo = photo_file
p.save!
end
...
end
Still getting the error periodically, though.
Still more info:
I noticed that when I first run my script it's able to do a large amount of files (12 or so). As I continue to run it the number decreases to where I can only do 2 at a time. I'm not sure what I'm doing to make it "reset" and process more. But I imagine that's the key.
This monkey patch solved the issue:
http://github.com/thoughtbot/paperclip/issues/issue/262/
It sure looks to me like you're closing the File handle you opened before you read it out into paperclip.
File.open() with a block opens the file, passes it to the block, and closes it after block execution. This means it's likely closed before you call p.save!
Try doing all of your Photo creation inside your file block:
File.open(f, 'r') {|photo_file| Picture.create!(:photo => photo_file) }
Paperclip is a great upload plugin for Rails. Storing uploads on the local filesystem or Amazon S3 seems to work well. I'd just assume store files on the localhost, but the use of S3 is required for this app as it will be hosted on Heroku.
How would I go about getting all of my uploads/attachments from S3 in a single zipped download?
Getting a zip of files from the local filesystem seems straight forward. It's getting the files from S3 that has me puzzled. I think it may have something to do with the way that rubyzip handles files referenced by URL. I've tried various approaches but can't seem to avoid errors.
format.zip {
registrations_with_attachments = Registration.find_by_sql('SELECT * FROM registrations WHERE abstract_file_name NOT LIKE ""')
headers['Cache-Control'] = 'no-cache'
tmp_filename = "#{RAILS_ROOT}/tmp/tmp_zip_" <<
Time.now.to_f.to_s <<
".zip"
# rubyzip gem version 0.9.1
# rdoc http://rubyzip.sourceforge.net/
Zip::ZipFile.open(tmp_filename, Zip::ZipFile::CREATE) do |zip|
#get all of the attachments
# attempt to get files stored on S3
# FAIL
registrations_with_attachments.each { |e| zip.add("abstracts/#{e.abstract.original_filename}", e.abstract.url(:original, false)) }
# => No such file or directory - http://s3.amazonaws.com/bucket/original/abstract.txt
# Should note that these files in S3 bucket are publicly accessible. No ACL.
# works with local storage. Thanks to Henrik Nyh
# registrations_with_attachments.each { |e| zip.add("abstracts/#{e.abstract.original_filename}", e.abstract.path(:original)) }
end
send_data(File.open(tmp_filename, "rb+").read, :type => 'application/zip', :disposition => 'attachment', :filename => tmp_filename.to_s)
File.delete tmp_filename
}
You almost certainly want to use e.abstract.to_file.path instead of e.abstract.url(...).
See:
Paperclip::Storage::S3::to_file (should return a TempFile)
TempFile::path
UPDATE
From the changelog:
New in 3.0.1:
API CHANGE: #to_file has been removed. Use the #copy_to_local_file method instead.
#vlard's solution is ok. However I've run into some issues with the to_file. It creates a tempfile and the garbage collector deletes (sometimes) the file before it was added to the zip file. Therefor, I'm getting random Errno::ENOENT: No such file or directory errors.
So I'm using the following code now (I've kept the initial code variables names for consistency with the initial question)
format.zip {
registrations_with_attachments = Registration.find_by_sql('SELECT * FROM registrations WHERE abstract_file_name NOT LIKE ""')
headers['Cache-Control'] = 'no-cache'
#please note that using nanoseconds option in strftime reduces the risks concerning the situation where 2 or more users initiate the download in the same time
tmp_filename = "#{RAILS_ROOT}/tmp/tmp_zip_" <<
Time.now.strftime('%Y-%m-%d-%H%M%S-%N').to_s <<
".zip"
# rubyzip gem version 0.9.4
zip = Zip::ZipFile.open(tmp_filename, Zip::ZipFile::CREATE)
zip.close
registrations_with_attachments.each { |e|
file_to_add = e.file.to_file
zip = Zip::ZipFile.open(tmp_filename)
zip.add("abstracts/#{e.abstract.original_filename}", file_to_add.path)
zip.close
puts "added #{file_to_add.path} to #{tmp_filename}" #force garbage collector to keep the file_to_add until after the file has been added to zip
}
send_data(File.open(tmp_filename, "rb+").read, :type => 'application/zip', :disposition => 'attachment', :filename => tmp_filename.to_s)
File.delete tmp_filename
}