问题
Some time ago I wrote a question regarding the use of temporary files within a rails app. On thar particular case, I decided to use tempfile
This causes a problem if I also want to use the x-sendfile
directive (as a parameter in Rails 2, or as a configuration option in Rails 3) so that the file sending is handled by my web server directly, not my rails app.
So I thought about doing something like this:
require 'tempfile'
def foo()
# creates a temporary file in tmp/
Tempfile.open('prefix', "#{Rails.root}/tmp") do |f|
f.print('a temp message')
f.flush
send_file(f.path, :x_sendfile => true) # send_file f.path in rails 3
end
end
This setup has one issue: the file is deleted before being sent!
On one hand, tempfile
will delete the file as soon as the Tempfile.open
block is over. On the other, x-sendfile
makes the send_file call asynchronous - it returns very quickly, so the server hardly has time to send the file.
My best possible solution right now involves using non-temporary files (File instead of Tempfile), and then a cron task that erases the temp folder periodically. This is a bit inelegant since:
- I have to use my own tempfile naming scheme
- Files stay on the tmp folder longer than they are needed.
Is there a better setup? Or, is there at least a "success" callback on the asynchronous send_file
, so I can erase f when it's done?
Thanks a lot.
回答1:
Given that Rails3 uses x-sendfile when it is available, and there is no way to deactivate it, you just can't use send_file with a library such as TempFile. The best option is the one I mentioned in the question: use a regular File, and have a cron task that removes old temp files periodically.
EDIT: The removal of unused files has now been easier to deal with with the maid gem:
https://github.com/benjaminoakes/maid
回答2:
don't put send_file in block.
f = Tempfile.new('prefix', "#{Rails.root}/tmp")
f.print('a temp message')
f.close
send_file(f.path, :x-sendfile => true)
then using another script to cleanup tempfile
回答3:
How about the file-temp gem? https://github.com/djberg96/file-temp
require 'file/temp'
fh = File::Temp.new(false)
fh.puts "world"
fh.close # => Tempfile still on your filesystem
Like the zzzhc's answer, you would need to manage cleanup externally
回答4:
You can undefine Tempfile instance's finalizer so that your file never gets deleted when the instance is detroyed and then let the chron task handle it.
require 'tempfile'
def foo()
# creates a temporary file in tmp/
Tempfile.open('prefix', "#{Rails.root}/tmp") do |f|
f.print('a temp message')
f.flush
ObjectSpace.undefine_finalizer(f) # 'disables' deletion when GC'ed
send_file(f.path, :x_sendfile => true) # send_file f.path in rails 3
end
end
来源:https://stackoverflow.com/questions/6043313/rails-x-sendfile-temporary-files