send_file return value - ruby-on-rails

Does the send_file method in Rails give a return value? I'd like to do one thing if the sending is successful, and another thing if the sending is not successful. I looked at the documentation at this link, but did not find anything relevant.

No, there is no way to confirm download completion or success with send_file. From this question: Can we find out when a Paperclip download is complete? :
send_file creates the file and then passes a special header to tell
the webserver telling it what to send. Rails doesn't actually send the
file at all, it sets this header which tells the webserver to send the
file but then returns immediately, and moves on to serve another
request. To be able to track if the download completes you'd have to
occupy your Rails application process sending the file and block until
the user downloads it, instead of leaving that to the webserver (which
is what its designed to do). This is super inefficient.
You may be able to do something using cookies and JavaScript on the client.
See this question: Rails File Download And View Update - Howto?

Related

Caching an HTTP request made from a Rails API (google-id-token)?

ok, first time making an API!
My assumption is that if data needs to be stored on the back end such that it persists across multiple API calls, it needs to be 1) in cache or 2) in a Database. is that right?
I was looking at the code for the gem "google-id-token". it seems to do just what i need for my google login application. My front end app will send the google tokens to the API with requests.
the gem appears to cache the public (PEM) certificates from Google (for an hour by default) and then uses them to validate the Google JWT you provide.
but when i look at the code (https://github.com/google/google-id-token/blob/master/lib/google-id-token.rb) it just seems to fetch the google certificates and put them into an instance variable.
am i right in thinking that the next time someone calls the API, it will have no memory of that stored data and just fetch it again?
i guess its a 2 part question:
if i put something in an #instance_variable in my API, will that data exist when the next API call comes in?
if not, is there any way that "google-id-token" is caching its data correctly? maybe HTTP requests are somehow cached on the backend and therefore the network request doesnt actually happen over and over? can i test this?
my impulse is to write "google-id-token" functionality in a way that caches the google certs using MemCachier. but since i dont know what I'm doing i thought i would ask.? Maybe the gem works fine as is, i dont know how to test it.
Not sure about google-id-token, but Rails instance variables are not available beyond single requests and views (and definitely not from one user's session to another).
You can low-level cache anything you want with Rails.cache.fetch this is put in a block, takes a key name, and an expiration. So it looks like this:
Rails.cache.fetch("google-id-token", expires_in: 24.hours) do
#instance_variable = something
end
If the cache exists and it is not past its expiration date/time, Rails grabs it from the cache; otherwise, it would make your API request.
It's important to note that low-level caching doesn't work with mem_store (the default for development) and so you need to implement a solution with redis or memcached or something like that for development, too. Also, make sure the file tmp/cache.txt exists. You can run rails dev:cache or just touch it to create it.
More on Rails caching

Using Google's text to speech API with Hyperstack

I would like to use the Google text-speech API to let my user type text into a text control, and then click a button which would send the text to my Rails server, where it would use the Google TextToSpeach API to create an mp3 file of that speech.
The Google API looks very simple to use: https://cloud.google.com/text-to-speech/docs/create-audio
In a traditional Rails application, I would write an API to pass the text to be transcribed and would expect that API call to return the path to the MP3 file created for the user to download.
It seems that a Hyperstack Isomorphic Operations would be the right approach for this, but how do I ensure the operation only runs on the server and not on the client though and how do I get the output value of the Operation (ie the file created) so I can display it in the browser for the user to download?
I should stress that I only need the Google API to Create the Audio file on the server (not play it). The user will then download the created file so their own use.
An operation is not going to help you here. Why?
Because unless you know a trick I don't, the only way to play an audio file without a lot of extra work, is to point an HTML audio tag's source at a url on the server.
This is then very easily done by a standard rails controller method that decodes the string from the URL params and returns the mp3 file in the response body.
For example /utils/text2speech.mp3?text=Hello%020There would just return the MP3 file.
Just to fully answer your question however, the Hyperstack::ServerOp class is a subclass of Operation that only runs on the server, but can be called from the client.
Too bad its no help here :-)

Write public file in controller; remote access hangs until action completes

When implementing a controller action such as the following:
def create_file
File.open('public/test.txt', "w+") do |f|
f.write('test')
end
sleep(60)
head :no_content
end
The file domain/test.txt will be accessible after the action completes; however, any attempts to access this URL before the action returns (such as during the sleep() call) seem to hang until it is finished.
I have use cases where I'd like to create publicly-accessible files based on user input, call a third-party API that requires passing a URL to such a file (no option to send the data iself in this case), then remove the file before the action is done. Unfortunately, this seems to be impossible thanks to the file not actually be accessible until the action is finished.
Is there some way around this in Rails, some type of flush call or route refresh or handle closer? I'm not sure why it's even hanging in this case. Or am I going to have to use separate actions to create and process the file (assuming I don't want to store it on a static, non-Rails site on the same server)?
Seems the problem was, as comments indicate, caused by only having one thread available to serve requests in development mode. Solution was to add config.threadsafe! to config\environments\development.rb and to launch thin with the --threaded option.

Rails, given an AWS S3 URL, how to use a controller to send_data / file to the requestor

Given an Amazon S3 URL, or any URL that is a direct URL to a file. In my controller, given this URL, I want to send the user the file, whatever it is w/o redirecting.
Is this possible?
If I understand your question correctly, I don't think that's possible from your end. That's why many sites say "right click to save" or something along those lines. Some sites even have links to videos that say "click to download" but when I click the link they start streaming. These are due to MY settings (ie. the settings on the user's client). You can't control that.
If what you're trying to do is HIDE the location of a file...
Send files back to the user - Usually,
static files can be retrieved by using
the direct URL and circumventing your
Rails application. In some situations,
however, it can be useful to hide the
true location of files, particularly
if you're sending something of value
(e-books, for example). It may be
essential to only send files to logged
in users too. send_file makes it
possible. It sends files in 4096 byte
chunks, so even large files can be
sent without slowing the system down.
From an old blog post

Can we find out when a Paperclip download is complete?

I have an application where I need to know when a user's Rails/Paperclip file download is complete. My app is set up to interact with Amazon S3 and I need to run a javascript function when the user has received the completed file.
How can I do this?
Tracking weather or not the download completes is hard, especially in Javascript. There are a few blurred lines in your question which makes me think its not possible.
First, send_file passes a special header to tell the webserver telling it what to send. See the send_file docs. Rails doesn't actually send the file at all, it sets this header which tells the webserver to send the file but then returns immediately, and moves on to serve another request. To be able to track if the download completes you'll have to occupy your Rails application process sending the file and block until the user downloads it, instead of leaving that to the webserver (which is what its designed to do). This is super inefficient.
Next, how can you still be on a page to execute a javascript function if you are downloading a file? Your user clicks the file download link and is taken to wherever the file is, weather that be a send_file from Rails or a redirect to S3 or whatever, they are no longer on the page they came from. If you are thinking about the way Chrome or Firefox works where the download goes into a download manager and the user stays on the page, theres no more interaction with the server on the old page! If you want that page to be notified of download completion, then you'd need a periodic check or long poll to the server to see if the download is done.
I think you'd be better served by redirecting to the S3 file and setting a session variable to redirect the user to where you want them to go after the download is complete so that the next time they visit any page they are back in your planned flow.
Hope this helps!

Resources