I have a method export_csv in controller.
def export_csv
if params[:from_date].present? && params[:to_date].present?
@users = User.where("created_at between ? and ?", params[:from_date], params[:to_date])
if !@users.blank?
users_csv = User.to_excel(@users)
send_data(users_csv, :type => 'text/csv', :filename => 'users.csv')
flash.now[:success] = "Successfully downloaded the report!"
else
flash.now[:notice] = "No records over selected duration!"
end
else
flash.now[:notice] = "Select from and to date.."
end
end
The file is downloaded but the page is not refreshed or reloaded. Due to this, the flash message stays as it was on the page even after the file is downloaded.
I have gone through few sites and found that send_data automatically renders the view and so other redirect or render can't be used.
Is there a way to reload the page after send_data.?
send_data
sets the whole server response, so the browser is just receiving a CSV file, not a web page. This is why your flash message is not displaying. An alternative could be to generate a temporary CSV file (with random name) and provide back a link to it:
def export_csv
if params[:from_date].present? && params[:to_date].present?
@users = User.where("created_at between ? and ?", params[:from_date], params[:to_date])
if !@users.blank?
#Create temporary CSV report file and get the path to it.
csv_file_path = create_csv_file(User.to_excel(@users))
#Change the flash message a bit for requesting the user
#to click on a link to download the file.
flash.now[:success] = "Your report has been successfully generated! Click <a href='#{csv_file_path}'>here</a> to download".html_safe
else
flash.now[:notice] = "No records over selected duration!"
end
else
flash.now[:notice] = "Select from and to date.."
end
end
Of course you should implement the function create_csv_file
. To avoid keeping old files in your server, you could implement a new method, say download_report
which would read the file, send back to the client with send_data
and finally delete it.
EDIT
Pseudocode for the functions mentioned above:
require 'tempfile'
def create_csv_file(data)
#Create a temporary file. If you omit the second argument of Tempfile.new
#then the OS's temp directory will be used.
tmp = Tempfile.new('report', 'my/temp/dir')
tmp.write(data)
tmp.close
return tmp.path
end
#Method in controller for downloading the file. I omit checks and/or security issues.
def download_report
#Warning: a mechanism should be implemented to prevent the remote
#client from faking the path and download other files.
#A possible solution would be providing not only the file path but also a
#hash with a secret key to validate the path. Function create_csv_file()
#should, then, return a hash in addition of a path.
path = params[:report]
file = File.open(path, "rb")
contents = file.read
file.close
send_data(contents , :type => 'text/csv', :filename => 'users.csv')
file.unlink #Delete file
end