When a click on the 'View CSV' link on my site the csv downloads but the content of the csv is in Chinese instead of English. How do I ensure the language of what I'm passing through the send_data function doesn't change? Thanks for your help!
I have the following function in my controller:
def get_data_visit
#csv_string = CSV.generate do |csv|
csv << ["row", "of", "CSV", "data"]
end
send_data Iconv.conv('iso-8859-1//IGNORE', 'utf-8', #csv_string), filename: "something.csv"
end
And the following function in my view:
<%= link_to "View CSV", get_data_visit_admin_stats_path %>
Ie. ["row", "of", "CSV", "data"] becomes 潲ⱷ景䌬噓搬瑡 and I would like it to stay in English.
I had to ensure libre office was reading utf-8 (changed in a drop down), then it worked.
Related
I am building a very simple web tool where user can upload a CSV file, which is then processed and the result CSV can be immediately downloaded.
The upload form:
<%= form_tag '/upload', multipart: true do %>
<%= file_field_tag :csv %>
<%= submit_tag 'Import CSV' %>
<% end %>
The upload and download actions:
def upload
original_csv = params[:csv]
p original_csv.path # /var/folders/71/chp2vrc92_19b3jt2fcwhvp80000gn/T/RackMultipart20181025-11469-25guh5.csv
redirect_to result_path(file_path: original_csv.path)
end
def result
p params[:file_path] # /var/folders/71/chp2vrc92_19b3jt2fcwhvp80000gn/T/RackMultipart20181025-11469-25guh5.csv
output_csv = CSV.generate do |csv|
CSV.foreach(params[:file_path], headers: true) do |row|
#############################################
# "No such file or directory # rb_sysopen" #
# exception is thrown #
#############################################
# each row data is being processed here
csv << row
end
end
# Download the file into user's computer
send_data output_csv
end
As you can see from the comments, this method doesn't work because the temp file path no longer exists in result action. How can I go about this without touching db at all.
Uploaded files are stored as temp files by the application. That means once the request has ended the temp file is automatically deleted. Therefore it doesn't exist anymore when the next page is requested.
One option would be to copy the file by yourself to another location and make it a "real" file in the file system that isn't deleted automatically anymore. But that has downsides too: Now you are responsible to manage and delete these files by yourself too. That means you need to generate unique files names and pass them to the next request and you need to ensure that the file is deleted after it was downloaded otherwise these files would slowly consume all space on your server's disk. Furthermore, this doesn't scale to multiple servers and will only work for small applications running on one server.
A better option might be to just do the upload, the processing and the download in one request, without any redirect. As long as the processing can be done in a reasonable time and in memory this might be a good option to avoid complexity.
def upload
original_csv = params[:csv]
output_csv = CSV.generate do |csv|
CSV.foreach(original_csv.path, headers: true) do |row|
# process data
csv << row
end
end
send_data output_csv
end
Try this:
def upload
result(params[:csv])
end
def result(fpath=params[:file_path])
output_csv = CSV.generate do |csv|
CSV.foreach(fpath, headers: true) do |row|
csv << row
end
end
# Download the file into user's computer
send_data output_csv
end
I have a rails project which is exporting some csv data into excel. On some instances excel is outputting special characters.
ex.
test 1 & test 2 & test 2
reads in excel as
test 1 & test 2 & test 2Â
My default CSV encoding is set to UTF-8 and I have played around with a number of other encoding settings although none of them have seemed to solve this issue.
Here is where the csv gets generated.
<% headers = default_headers %>
<%= CSV.generate_line(headers).strip %>
<% #activities.each do |activity| %>
<% has_permission = #_controller.is_activity_permissioned_to_user?(activity, current_user) %>
<% row = activity_generate_csv_row_data(activity, headers, has_permission, preferences) %>
<%= CSV.generate_line(row).gsub(/\A""/,'').strip.html_safe %>
<% end %>
and in my controller.
format.csv {
headers['Content-Disposition'] = "attachment; filename=\"
{report_name}.csv\""
headers['Content-Type'] ||= 'text/csv'
}
Every solution i've tried has failed. I really just can't figure out how to fix this.
Try to concatenate a Byte Order Mark string with your CSV string, like:
BOM = "\uFEFF"
def some_csv_string_generating_func
...
return BOM + a_csv_string
end
This will make Excel show the CSV file correctly.
Also, I would advice against having all the CSV generation logic/code on the view, but on a helper class/module or the like.
I have the following in my view:
<%= form_tag import_list_path, multipart: true do %>
<%= file_field_tag(:file) %>
<%= submit_tag(:Submit) %>
<% end %>
I have this in my controller:
def import
require 'csv'
csv = CSV.load params[:file].tempfile.read
CSV.new(csv.tempfile, :col_sep => ",", :return_headers => false).each do |column|
name_array << column[5]
end
redirect_to(:index)
end
I'm just trying to store a temporary CSV file in memory and do some actions on it, essentially using it to pull in information to be used in consuming a web service later.
This is the error I receive:
cannot load such file -- Column1,Column2,Column3,Column4,Column5,Column6,Column7,etc....
How can I change my controller to not throw this error?
That should do it.
def import
require 'csv'
CSV.new(params[:file].tempfile, :col_sep => ",", :return_headers => false).each do |column|
name_array << column[5]
end
redirect_to(:index)
end
Another notice: Dont put your logic in your controller it belongs in the model ;)
//
That menas you should write a method in your model that deals with the data and only refere the path to the csv file as a parameter of the method. The model is there as an interface between you app and the database and for the things done in the app. The View is there to display your stuff and the controller is the thing that connects both.
I have a form that is attempting to read in a JSON file for parsing/actions/etc. I'm having problems getting it to read in the controller.
View:
<%= form_tag({:controller => :admins, :action => :upload_json}, {:multipart => true, :method => :post}) do |f| %>
<%= file_field_tag 'datafile' %>
<%= submit_tag "Upload" %>
Controller:
def upload_json
file_data = params[:datafile]
File.read(file_data) do |file|
file.each do |line|
## does stuff here....
end
end
end
A similar function works in my seed.rb file when I'm seeding data - just can't get it to read in an uploaded file.
The error I'm getting is: can't convert ActionDispatch::Http::UploadedFile into String.
Thanks in advance for the help!
Figured it out. Needed to change:
file_data = params[:datafile]
to
file_data = params[:datafile].tempfile
And decided to use the .open function to change:
File.read(file_data) do |file|
to
File.open(file_data, 'r') do |file|
params[:datafile] is an instance of ActionDispatch::Http::UploadedFile class with tempfile attached with that.To open the tempfile
You try something like
File.open(params[:datafile].path) do |file|
#your stuff goes here
end
Open the uploaded file using path.
params[:datafile] is an instance of ActionDispatch::Http::UploadedFile class and you'll need to get at the stored file by calling path to properly process it.
Additionally, File.read will not get you the line-by-line processing you're looking for. You need to change that to File.open.
Try this:
Controller
def upload_json
uploaded_datafile = params[:datafile]
File.open( uploaded_datafile.path ) do |file|
file.each_line do |line|
# Do something with each line.
end
end
end
Alternative Style
def upload_json
File.foreach( params[:datafile].path ) do |line|
# Do something with each line.
end
# FYI: The above method block returns `nil` when everything goes okay.
end
I want to give my users the ability to export a table to CSV.
So in my controller, I've added on top of the file:
respond_to :html, :js, :csv
I'm also setting the headers if the requested format is csv:
if params[:format] == 'csv'
generate_csv_headers("negotiations-#{Time.now.strftime("%Y%m%d")}")
end
Code for generate_csv_headers(in application_controller) is:
def generate_csv_headers(filename)
headers.merge!({
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Content-Type' => 'text/csv',
'Content-Disposition' => "attachment; filename=\"#{filename}\"",
'Content-Transfer-Encoding' => 'binary'
})
end
I've also created a view named index.csv.erb to generate my file:
<%- headers = ["Id", "Name"] -%>
<%= CSV.generate_line headers %>
<%- #negotiations.each do |n| -%>
<%- row = [ n.id,
n.name ] -%>
<%= CSV.generate_line row %>
<%- end -%>
I don't have any error, but it simply displays the content of the CSV file, while I'd expect a prompt from the browser to download the file.
I've read a lot, but could not find anything that'd work.
Do you have an idea?
thanks, p.
I'm still unsure about why this fixed the issue, but it did.
I changed the link in the view to
<%= link_to "Export to csv", request.parameters.merge({:format => :csv})%>
and it now works!
I'm not sure you have to do it this way, but if you generate and save the file, you can use send_file to send it to the browser. See http://api.rubyonrails.org/classes/ActionController/Streaming.html
You might be interested in this gem I made called CSV shaper that allows you to create CSV output using a really nice Ruby DSL.
It will also handle setting the response headers correctly, while allowing filename customisaton.
https://github.com/paulspringett/csv_shaper