Reputation: 9822
So this is probably a simple question, but I've never done it before.
I have a Rails action that queries a database and creates a csv string from the query result.
I'd like to take the query string, put it into a .csv file, and when the user makes the http request associated with this method, the .csv file will download onto the user's machine.
How can I do this?
UPDATE
The file is sending from rails, but my angular app on the front end (that requested the csv) is not downloading it.
Here is the angular code I'm using to request the file from the rails app
$scope.csvSubmit = function() {
var csv = $.post('http://ip_addr:3000/api/csv', { 'input': $scope.query_box });
csv.done(function(result){
//empty - after the request is sent I want the csv file to download
})
}
Upvotes: 2
Views: 6884
Reputation: 6241
Use send_data
to generate a downloadable file from a string in just one line:
send_data @your_data, type: 'text/csv', disposition: 'attachment', filename: 'books.csv'
Upvotes: 0
Reputation: 597
You can use the send_file
method, passing the path to the file as the first argument, as see in Rails documentation.
UPDATE
You can use a temporary file to save the CSV, like this:
require 'tempfile'
# automatically creates a file in /tmp
file = Tempfile.new('data.csv', 'w')
file.write('my csv')
file.close
send_file(file.path)
# remove the file from /tmp
file.unlink
UPDATE 2: AngularJS download
There are two ways to accomplish this: you can add a hidden href to download the file in the page and click it, or redirect the user to the Rails URL that sends the file when he clicks in the button. Note that the redirect will use parameters in the url, so it won't work well depending on the structure of query_box
.
To add a hidden href to the page with the CSV:
$scope.csvSubmit = function() {
var csv = $.post('http://ip_addr:3000/api/csv', { 'input': $scope.query_box });
csv.done(function(result){
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:attachment/csv,' + encodeURI(result);
hiddenElement.target = '_blank';
hiddenElement.download = 'filename.csv';
hiddenElement.click();
})
}
To use the redirect:
$scope.csvSubmit = function() {
var url = 'http://ip_addr:3000/api/csv/?' + 'input=' + encodeURI($scope.query_box);
window.location = url;
}
Upvotes: 5
Reputation: 571
I've had to do this plenty of times before. You need to set the response headers to get the browser to force the download.
I like to use the comma gem for rendering csv. Using the gem all you need to do is add the following lines to your controller action.
respond_to do |format|
format.csv do
response.headers['Content-Type'] = 'text/csv'
response.headers['Content-Disposition'] = 'attachment; filename=books.csv'
render :csv => Book.limited(50)
end
end
Then you just use the csv format and it works.
If you don't want to use comma. Just change the render line to render your csv string:
render :plain => csv_string_variable
Upvotes: 2