Getting rendered images to the browsers in Rails - ruby-on-rails

I am writing a Rails app that processes data into a graph (using Scruffy). I am wondering how can I render the graph to a blog/string and then send the blog/string directly to the the browser to be displayed (without saving it to a file)? Or do I need to render it, save it to a file, then display the saved image file in the browser?

I think you will be able to use send_data for this purpose:
send_data data_string, :filename => 'icon.jpg', :type => 'image/jpeg', :disposition => 'inline'
If you put this in a controller action - say show on a picture controller, then all you need do is include the following in your view (assuming RESTful routes):
<%= image_tag picture_path(#picture) %>

I wonder if sending direct to the browser is the best way? If there is the possibility that users will reload the page would this short circuit any cache possibilities? I ask because I really don't know.

"If there is the possibility that users will reload the page would this short circuit any cache possibilities?"
No - whether you're serving from a file system or send_data doesn't matter. The browser is getting the data from your server anyway. Just make sure you've got your HTTP caching directives sorted out.

Related

How best to setup rails with only one view?

I'm working on a personal RoR project with an interesting sort of problem: the whole app only needs one HTML template.
Basically, the whole app is presented through HTML5 canvas (it's going to be a game of sorts). But I'd still like there to be URLs for accessing specific resources, such as '/player/1'.
So what's the best, DRYest way to do this? I'd really hate to specify the template in every action in the controllers.
render :file => "layout_file", :layout => false
You could define your view in app/views/layout/application.html.erb and leave all the others empty, but that wouldn't avoid the reloading of pages.
You should also have all your methods respond in json format.
Or just an old good:
render :nothing => true
at the end of your methods.

Batch downloads in Ruby on Rails

I've got a Ruby on Rails app and I was wondering what the best way do do batch downloads would be? At any given time I've got a set of URLs that point to files that I want my users to be able to download, but based on a search of those files done by my users I want them to be able to download a subset of those files, say the search result, in one process instead of having them download them individually. This set of files may potentially number in the thousands. My real question is, based on an array of URLs, how do I enable my app to download that entire set at once? I of course did some Googling and I came up with the solution below. It doesn't seem to work for me, but it did seem to work for those who posted it as a solution for a similar problem. Any and all input would be appreciated.
# controller code
def download
for n in 0..(#urls.length - 1)
send_file(#urls[n], :type => "video/quicktime",
:filename => #urls[n].basename,
:disposition => "attachment")
end
end
# view code
<%= link_to 'Download them all', :controller => 'my_controller',
:action => 'download' %>
This approach seems to me that it will use a huge amount of memory, especially with 1000s of files downloaded per user at a time. Perhaps instead you should ZIP the files in the background after they click a link and then send it to the user or email them the location of where the ZIP's at. It'll still use a lot of memory to ZIP that many files, so perhaps offloading that task to another server would be good.

Rails - any fancy ways to handle 404s?

I have a rails app I built for an old site I converted from another cms (in a non-rails language, hehe). Most of the old pages are mapped to the new pages using routes.rb. But there are still a few 404s.
I am a rails newb so I'm asking if there are any advanced ways to handle 404s. For example, if I was programming in my old language I'd do this:
Get the URL (script_name) that was being accessed and parse it.
Do a lookup in the database for any keywords, ids, etc found in the new URL.
If found, redirect to the page (or if multiple records are found, show them all on a results page and let user choose). With rails I'd probably want to do :status => :moved_permanently I'm guessing?
If not found, show a 404.
Are there any gems/plugins or tutorials you know of that would handle such a thing, if it's even possible. Or can you explain on a high level how that can be done? I don't need a full code sample, just a push in the right direction.
PS. It's a simple rails 3 app that uses a single Content model.
Put this in routes (after every other route that you have, this will capture every url)
match '*url' => 'errors#routing'
And now in errors controller in routing action you can implement any fancy logic that you want, and render a view as always (you might want to add :status => 404 to the render call). Requested url will be available in controller as params[:url].
There is an ugly way of doing this:
render :file => "#{RAILS_ROOT}/public/404.html", :layout => false, :status => 404
Maybe someone can come with a better solution.

MIME Types and url_for in Rails

I have a nice RESTful controller in my Rails application that uses responds_to to distinguish between requests for HTML and CSV requests, serving the HTML if one uses the URL normally, and the CSV if one adds ".csv" to the end of the URL.
In my view layer ERB file, I want to have a link to the CSV. I could just get the URL for the appropriate action normally and then just add ".csv" to the end of it, but that seems kinda hacky. I don't, however, see anthing in the url_for docs that would allow me to do this more cleanly.
Is there something I'm missing, or am I just stuck with something like this?
Download CSV
Thanks for any insight!
url_for #topic, :format => :csv
is probably what you are looking for

How to store private pictures and videos in Ruby on Rails

Here's a story:
User A should be able to upload an image.
User A should be able to set a privacy. ("Public" or "Private").
User B should not be able to access "Private" images of User A.
I'm planning to user Paperclip for dealing with uploads.
If I store the images under "RAILS_ROOT/public/images", anyone who could guess the name of the files might access the files. (e.g., accessing http://example.com/public/images/uploads/john/family.png )
I need to show the images using img tags, so I cannot place a file except public.
How can I ensure that images of a user or group is not accessible by others?
(If I cannot achieve this with Paperclip, what is a good solution?)
You may make your rails server output the contents of image files. This is done via a controller action (most of actions print HTML, but this one will print JPG, for example).
Then you may use your authorization system to restrict access on controller level!
class ImagesController
#Default show Image method streams the file contents.
#File doesn't have to be in public/ dir
def show
send_file #image.filename, :type => #image.content_type,
:disposition => 'inline'
end
# Use your favorite authorization system to restrict access
filter_access_to :show, :require => :view, :attribute_check => :true
end
In HTML code you may use:
<img src="/images/show/5" />
I would have Paperclip use S3 on the back-end, set uploaded files to private, and then use "Query String Request Authentication Alternative" to generate the URLs for my image tags.
http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAuthentication.html
Here's how I did this in a similar application.
Store your images on Amazon S3 instead of the local file system. Paperclip supports this.
Set your :s3_permissions to "private" in your Paperclip options
In your Image model, define a method that let's you output an authorized, time-limited url for the image.
Mine looks like this:
def s3_url(style = :original, time_limit = 30.minutes)
self.attachment.s3.interface.get_link(attachment.s3_bucket.to_s, attachment.path(style), time_limit)
end
You can then show images to people only if they're authorized to see them (implement that however you like)–and not have to worry about people guessing/viewing private images. It also keeps them from passing URLs around since they expire (the URL has a token in it).
Be warned that it takes time for your app to generate the authorized urls for each image. So, if you have several images on a page, it will affect load time.
If you want to host files yourself, you can perform authentication at the controller level as has been suggested. One of my applications has an AssetController that handles serving of files from the 'private' directory, for example.
One thing I wanted to add is that you should review this guide for setting up X-Sendfile, which will let your application tell the web server to handle actually sending the files. You'll see much better performance with this approach.

Resources