Forum: Ruby on Rails send_file and remote files

Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-21 18:04
Hello,

My first post here. I'm quite new to Ruby.

I'm making a Flash application that loads external files
from other servers onto the user's hard disk.
That's why I need a way to connect to the remote locations
over absolute http links; so I can monitor the progress inside
my Flash app.  So this code should act as a file serving proxy.
Flash has some security restrictions, that will not allow the
loading of external files from other domains.


What I've got is this (not working, throws an error).
I used this file as an example:

   "Cannot read file http://www.twin-diamonds.com/pic/rubies.jpg"


class StreamDataController < ApplicationController
        def index
                send_file(params[:file],:filename => params[:name],
:stream => 'true', :buffer_size => '4096')
        end
end
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-21 22:37
No one ?
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2007-02-22 00:18
Mister Twister wrote:
> What I've got is this (not working, throws an error).
> I used this file as an example:
>
>    "Cannot read file http://www.twin-diamonds.com/pic/rubies.jpg"
>
>
> class StreamDataController < ApplicationController
>         def index
>                 send_file(params[:file],:filename => params[:name],
> :stream => 'true', :buffer_size => '4096')
>         end
> end

send_file is meant to work with local files.  So ruby tries to open that
string as a local filename.  You might try send_data with a string of
data instead.

  #environment.rb
  require 'open-uri'

  #controller
  def index
    data = open(params[:file])
    send_data data, :filename => params[:name], ...
  end
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2007-02-22 00:19
Alex Wayne wrote:
>   #environment.rb
>   require 'open-uri'
>
>   #controller
>   def index
>     data = open(params[:file])
>     send_data data, :filename => params[:name], ...
>   end

Oops, I think that should be:

  #controller
  def index
    data = open(params[:file]).read
    send_data data, :filename => params[:name], ...
  end
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 00:20
That way I cannot set the buffer.
That's kind of anoying, because now it takes
a while to load the files ( > 10mb ) into
the memory of the server machine.

I've got code working like that, but I really
want to make use of the buffer.
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2007-02-22 00:27
Mister Twister wrote:
> That way I cannot set the buffer.
> That's kind of anoying, because now it takes
> a while to load the files ( > 10mb ) into
> the memory of the server machine.
>
> I've got code working like that, but I really
> want to make use of the buffer.

Then you may want to write the file to a temp directory and then send it
with send_file

  data = open(params[:file])
  filename = "#{RAILS_ROOT}/tmp/my_temp_file"

  File.open(filename, 'r+') do |f|
    f.write data.read
  end

  send_file filename, ...options...
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 00:44
I think that leaves me with the same issue, no ?

I will have to download the file first to my own server.
And then serve them to my clients.
The same thing happens with send_data, but only to the
server's memory, in stead of writing the data to the hard disk.

The good thing is that I can cache the files this way.
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 00:52
I tried your code but it gives:

No such file or directory - "http://www......"
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2007-02-22 00:56
Mister Twister wrote:
> I think that leaves me with the same issue, no ?
>
> I will have to download the file first to my own server.
> And then serve them to my clients.
> The same thing happens with send_data, but only to the
> server's memory, in stead of writing the data to the hard disk.
>
> The good thing is that I can cache the files this way.

I don't think you will be able to do this from a rails app.  I just
don't see a way that you can download the file the file in chunks and
sending those chunks back out before the file has downloaded completely.

Maybe some other background process on your server could handle a
request like this, but I don't think it will work from within Rails.

Although, it's disturbing that I think that is the first time I have
ever said that.
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2007-02-22 00:58
Mister Twister wrote:
> I tried your code but it gives:
>
> No such file or directory - "http://www......"

did you remember this from my previous post?

  #environment.rb
  require 'open-uri'

open-uri lets the "open" method work with urls.
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 01:07
I've added those lines too now. sorry about that.

I have another error now.

No such file or directory - /var/www/vhosts/..../railsapp/tmp/download

When I send it to tmp/downloads ( I created that folder ),
then it says:

Is a directory - /var/www/vhosts/.../railsapp/tmp/downloads
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2007-02-22 01:32
Mister Twister wrote:
> I've added those lines too now. sorry about that.
>
> I have another error now.
>
> No such file or directory - /var/www/vhosts/..../railsapp/tmp/download

Well that path isn't vary well formed.  That '....' should probably be
'../..', so adjust the way you are constructing that path accordingly.

> When I send it to tmp/downloads ( I created that folder ),
> then it says:
>
> Is a directory - /var/www/vhosts/.../railsapp/tmp/downloads

You must supply the full filename of the file to write with File.open.
If you want to use the same filename as the one being downloaded, try
something like this, which will get everything to the right of the last
'/' in the url.

  url = 'http://foo.com/index.html'
  filename = url.split('/').last
  full_path = "#{RAILS_ROOT}/tmp/#{filename}"

  File.open(full_path, 'r+') {|f| ... }
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 01:36
The ...... is for obfuscating my paths.
The path is correct.

I'll try it now.

Tnx Alex ; )
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 01:41
The error still occurs.

No such file or directory -
/var/www/vhosts/....obfuscatedPath..../railsapp/tmp/downloads/rubies.jpg
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (squeegy)
on 2007-02-22 01:44
Mister Twister wrote:
> The error still occurs.
>
> No such file or directory -
> /var/www/vhosts/....obfuscatedPath..../railsapp/tmp/downloads/rubies.jpg

Are you sure that this path resolves to an existing directory?

  /var/www/vhosts/....obfuscatedPath..../railsapp/tmp/downloads/

The File.open method will not create directories, only files.  So all
directories must be in place.

If it still doesn't work, I dont know what else to tell you besides to
read up on file reading and writing in ruby.
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 02:03
I just started a brand new SSH session.
I typed in the path and it fully resolves ( excluding rubies.jpg off
course ).

I even chowned the tmp/downloads dir to 777
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 02:40
Alex, is this a typo ?



File.open(filename, 'r+') do |f|
    f.write data.read
end

shouldn't this be:

File.open(filename, 'w') do |f|
    f.write data.read
end

When I try this it gives me "can't convert String into Integer"
Cf6fd030015a87035997fd19374e7746?d=identicon&s=25 Mister Twister (webdevotion)
on 2007-02-22 03:10
I changed the "r+" attribute to "w"
and also discovered that buffer_size=>'4096' had to be buffer_size=>4096
without the quotes.

Thanks Alex !
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.