How to download image from url and display in view - ruby-on-rails

I am trying to download an image and displaying it in a view in rails.
The reason why I want to download it is because the url contains some api-keys which I am not very fond of giving away.
The solution I have tried thus far is the following:
#Model.rb file
def getUrlMethod
someUrlToAPNGfile = "whatever.png"
file = Tempfile.new(['imageprependname', '.png'], :encoding => "ascii-8bit")
file.write(open(data).read)
return "#{Rails.application.config.action_mailer.default_url_options[:host]}#{file.path}"
end
#This seems to be downloading the image just fine. However the url that is returned does not point to a legal place
Under development I get this URL for the picture: localhost:3000/var/folders/18/94qgts592sq_yq45fnthpzxh0000gn/T/imageprependname20130827-97433-10esqxh.png
That image link does not point anywhere useful.
My theories to what might be wrong is:
The tempfile is deleted before the user can request it
The url points to the wrong place
The url is not a legal route in the routes file
A am currently not aware of any way to fix either of these. Any help?
By the way: I do not need to store the picture after I have displayed it, as it will be changing constantly from the source.

I can think of two options:
First, embed the image directly in the HTML documents, see
http://www.techerator.com/2011/12/how-to-embed-images-directly-into-your-html/
http://webcodertools.com/imagetobase64converter
Second, in the HTML documents, write the image tag as usual:
<img src="/remote_images/show/whatever.png" alt="whatever" />
Then you create a RemoteImages controller to process the requests for images. In the action show, the images will be downloaded and returned with send_data.
You don't have to manage temporary files with both of these options.

You can save the file anywhere in the public folder of the rails application. The right path would be something like this #{Rails.root}/public/myimages/<image_name>.png and then you can refer to it with a URL like this http://localhost:3000/myimages/<image_name>.png. Hope this will help.

Related

Display PDF in iframe in RoR

I would like to display a pdf in an iframe in one of my Rails projects. My current code is <iframe src="tmp/data.pdf"></iframe>, but when I go to this page, I get the error: "No route matches [GET] /Users//development//tmp/data.pdf".
data.pdf is in this location, so I think I'm doing something wrong with my routes file, and maybe I have to route the file to a path appropriately. I've tried playing around with a few things, but haven't had much luck so far. Can anyone provide any help?
Rails only exposes the contents of the "public" subfolder to the webbrowser so no code/configuration can be downloaded by any user...
Try putting the file there and it should work.
UPDATE 1
Also you need to note, that the "public" part does not have to be included in the URL. So in your case the url would be just "/data.pdf".

How to change filename prompt text browser Save As dialog?

In my web page (rendered by Rails), I'd like to let the user right-click on a photo to bring up the browser's Save As dialog, to let the user save the photo to their hard drive.
However, the photos on my server have unusual filenames (long hex names) with no file extension. The filename prompt in the Save As dialog has this ugly filename. If the user hits save, they'll end up with a poorly-named file, with no file extension.
The web page is aware of the photo's real file name (the name that came off the camera, for example). Is there a way for me to programmatically override the Save As dialog's filename prompt with a filename of my choosing?
I'm aware of the Content-Dispostion header, and that via this header a filename can be specified. However, I think that in order to be able to make use of this header, I need to load/render the entire file to the browser. If the asset to be made available for download is a movie, that loading of the file could timeout the browser...like, if it's a 100meg video.
Thoughts?
-A
I think I understand the problem here because I encountered (and resolved) at least part of it myself not too long ago.
I have some large mp3's and I link to them on my website
A few problems
I needed to set my content-disposition header to attachment in order to prevent files from automatically streaming whenever a user clicked the download button
my files are on a remote server
my files are large (100MB)
large files can tie up rails controllers if not handled properly
Now, Michael Koziarsky advises in this article that the best way to keep your rails processes free when serving large files, is to create a download action in your controller, and the do something like this (note the use of x_sendfile=>true):
def download
send_file '/path/to/podcast.mp3', :type => 'application/octet-stream', :disposition => 'attachment', :filename=>'something.mp3', :x_sendfile=>true
end
:x_sendfile tells apache to let the file through without tying up a rails controller process. The rest of the code sets the filename and the content-disposition header.
Great, but I'm on heroku, like everyone else nowadays. So I can't use x_sendfile.
I found that I couldn't modify the nginx configuration file either as it's locked down by heroku so it was not possible to get x-accel-redirect (nginx equivalent of x-sendfile) working
So, I decided to add a perl script (see below) to the cgi-bin on our asset-host and this script sets the content-disposition to attachment and gives our file a name too.
Instead of doing a restful download like this:
link_to "download", download_podcast_path(#podcast.mp3)
we just link to the mp3 making sure that we go in through the cgi-bin so that the perl script gets called on every mp3 that leaves the server
# I'm using haml
%a{:href=>"http://afmpodcast.com/cgi-bin/download.cgi?ID=#{#podcast.mp3}"}
download
The result is that my rails controller is no longer called into action when someone downloads a file
I found the perl script here and chopped it up a bit to work for me:
#!/usr/local/bin/perl -wT
use CGI ':standard';
use CGI::Carp qw(fatalsToBrowser);
my $files_location;
my $ID;
my #fileholder;
$files_location = "../";
$ID = param('ID');
open(DLFILE, "<$files_location/$ID") || Error('open', 'file');
#fileholder = <DLFILE>;
close (DLFILE) || Error ('close', 'file');
print "Content-Type:application/x-download\n";
print "Content-Disposition:attachment;filename=$ID\n\n";
print #fileholder
My code, is on github but you'll likely have all sorts of problems using it on your machine as i make heavy use of ENV variables that I store in bashrc and I have no documentation or tests ^hides^
You could do some smart server side url rewrite, like for example rewriting foo.mpeg to youveryuglyfilenamewithoutextension.
Set the Content-Disposition to "attachment; filename="...that's fine. "attachment" explicitly means it's not to be rendered in the browser, file renaming works nonetheless (or possibly particularly for that case).
Based on your comments, you have a few problems.
You want to set the filename using your Rails app.
The file is on a remote host and your Rails app is acting as a middleman.
The file might be big, so you want the file to be sent out to the browser as you receive it instead of queuing the whole thing.
Streaming only with Rails is tricky for a few reasons.
You would need an HTTP client that lets you access the message body as you receive data instead of blocking until you have everything. Net::HTTP is not that client. I'm not sure what library would be better suited.
Once you have a more event-driven way to get your file in pieces, you can pass a proc to the render:
render :text => proc { |response, output| ... }
output can be used like an IO object. Some servers may buffer before sending anyway, though, so that's something to look out for.
It would be easier not handle the byte-shuffling in Rails.
If your webserver or the proxy in front of your webserver supports the X-REPROXY-URL HTTP header, your application can set that header and your webserver or proxy will stream the file.
Perlbal is the only proxy server I know of that supports that header out of the box.
An Apache2 module is also available.

Rails route rewriting

I think this is an easy question. I am using this useful Flash Document Reader called FlexPaper. I have it embedded in one of my Show pages. But when I click the a link on their tool bar to show the document in a new browser, it points to the following link:
http://example.com/intels/FlexPaperViewer.swf?ZoomTime=0.5&FitPageOnLoad=false&PrintEnabled=false&SwfFile=%2FPaper.swf
which doesn't work, I get the following error:
ActiveRecord::RecordNotFound in IntelsController#show
Couldn't find Intel with ID=FlexPaperViewer
but if I remove the "intels" from the path so the url looks like:
http://example.com/FlexPaperViewer.swf?ZoomTime=0.5&FitPageOnLoad=false&PrintEnabled=false&SwfFile=%2FPaper.swf
It works fine.
My question is what is the best way to handle this? Can you write a route that rewrites a url that starts with intels/FlexPaperViewer.swf and remove the intels prefix? What would that look like?
Is there a better option?
Juat a thought, how about placing the FlexPaperViewer.swf inside public/intels folder?
So the directory structure will be
<project-directory>/public/intels/FlexPaperViewer.swf
Doing this will make the link correct. It seems to be easier to do it this way.
Hopefully it helps.
EDIT
Another alternative will be to see how the link was generated, maybe there is a parameter that you can set when you embed the FlexPaper.
I am not aware of any route modification that can do what you want. Maybe someone else can help on this.

file_field_tag : what was the original file name?

My site allows users to upload csv files for processing. It all works
fine, but on the response I'd like to report something like "Your file
abc.csv processed OK".
Unfortunately I cannot seem to find the actual original file name in
the params, even though Firebug tells me it's part of the post.
Any tips?
Thanks....
Try using debug on the results of your form.
http://guides.rubyonrails.org/debugging_rails_applications.html#debug
As Jarrod mentions in the comments above. Use params[:file].original_filename
Funny thing is, my form has two file upload tags (file1 and file2). One comes in as a ActionController::UploadedTempfile and the other ActionController::UploadedStringIO.
This may be a rails bug but it doesn't matter to me as both have the original_filename method.

Correct practices for where to put images and static files in an ASP.NET MVC application?

There is a directory in the standard ASP.NET template "Content" where most people seem to be putting in images and css files etc.
For instance stackoverflow's logo:
(source: stackoverflow.com)
actually is refered to with a server path containing 'content' in the URL (just do View Source for any SO page and you'll see this). So they obviously are storing images in "content/images/...".
src="/Content/Img/stackoverflow-logo-250.png"
Edit: Sometime in the last 10 years they changed the path - but this is what it used to be.
I dont particularly like this. My HTML ends up with /content all over it, and its slightly harder to migrate existing pages that just have /image. Fortunately my stylesheet doesnt end up with content all over it, as long as I save it in content\site.css.
An alternative is to put an images directory in the root, but then you get images at the same level as Controllers and Views which is pretty horrible.
I'd wondered about trying to add a redirection rule like this :
routes.RedirectRoute(
"images rule",
"Images/{*}",
"Content/Images/{1}"); // this is NOT valid code - I made it up
But that code doesnt work because I just made it up. I could use a third party redirection/rewriting plug-in but I want to keep everything 'pure' within the MVC model.
What has anyone else found in this area? Or is everyone just happy with an extra ("/content".length) bytes in their source for every image they serve.
To be honest, I don't think its really something to worry about... "/Content" is going to make a pretty minimal contribution to your page size. If you still want to do it, here are some options:
Option 1, if you are running on your own server, is to check out the IIS URL Rewrite module: http://learn.iis.net/page.aspx/460/using-url-rewrite-module/
Option 2 is to use either RedirectResult, or ContentResult, to achieve the same effect in the MVC framework
First, map a "catchall" route under "Images/" to a controller action, like so
routes.MapRoute("ImageContent",
"Images/{*relativePath}",
new { controller = "Content", action = "Image" })
Make sure it is above your standard "{controller}/{action}/{id}" route. Then, in ContentController (or wherever you decide to put it):
public ActionResult Image() {
string imagePath = RouteData.Values["relativePath"]
// imagePath now contains the relative path to the image!
// i.e. http://mysite.com/Images/Foo/Bar/Baz.png => imagePath = "Foo/Bar/Baz.png"
// Either Redirect, or load the file from Content/Images/{imagePath} and transmit it
}
I did a quick test, and it seemed to work. Let me know in the comments if you have any problems!
It's usually better to put images under a different sub domain. The reason for this is browsers limit the number of connections per URL. So if you use http://static.mysiste.com now the browser can open more concurrent connections due to it being in a different URL.

Resources