I'm attempting to upload a csv file, parse it, and spit out a file for S3 or just pass to view. I use a file_field_tag to upload the csv. I thought file_field_tag passes an object that is a subclass of IO and would have all ruby IO methods such as "each_line". I can call "read" on the object (method of IO class) but not "each_line"... so how can I iterate over each line of a file_field_tag upload?
create method of my controller as:
@csv_file = params[:csv_file]
My show view which throws a no "each_line" method error:
<% @csv_file.each_line do |line| %> <%= line %> <% end %>
Yet I can use
<%= @csv_file.read(100) %>
I'm really confused what methods a file_field_tag upload params[] has... each_line, gets don't work... I can't seem to find a list of what I can use.
EDIT I worked around this by doing:
@csv_file = params[:csv_file].read.to_s
then iterated through with:
<% @sp_file.each_line do |line| %> <%= line %> <% end %>
EDIT 2 The file being uploaded has repeats the header after lines which don't contain a comma (don't ask)... So I find lines without a comma and call .gets (in my rb script independent of rails). Unfortunately I get an error about gets being a private method I can't call. Which goes back to my initial issue being. Aren't files a sub class of IO with IO methods like read_lines & gets?
@file_out = [] @file_in.each_line do |line| case line when /^[^,]+$/ @comp = line.to_s.strip comp_header = @file_in.gets.strip.split('') @file_out.push(@comp) end end
When you post a 'file_field' , the param returned to the controller has some special magic hooked in.
I.e. in your case you could this
<%= "The following file was uploaded #{params[:csv_file].original_filename}" %> <%= "It's content type was #{params[:csv_file].content_type}" %> <%= "The content of the file is as follows: #{params[:csv_file].read}" %>
So those are the three special methods you can call on params[:csv_file], or any params posted as the result of a successful 'file_field_tag' or 'f.file_field' in a view
Just remember that those are the three extra special things you can to to a param posted as a result of a file_field:
original_filename
content_type
read
You've clearly figured out how to do the read, the original_filename and content_type may help you out in the future.
EDIT
OK, so all you have is the read method, which will read the contents of the file uploaded.
contents = params[:csv_file].read
So now contents is a string containing the contents of the file, but nothing else is known about that file EXCEPT that it's a csv file. We know that csvs are delimited with '\r' (I think, I've done a lot of work with parsing csv's, but I'm too lazy to go check)
so you could do this:
contents = params[:csv_file].read contents.split("\r").each do |csvline| ??? end
EDIT 2
so here is the take away from this post
When you post a file_field to a controller, the most common thing to do with the contents of the uploaded file is 'read' it into a ruby String. Any additional processing of the uploaded contents must be done on that ruby String returned from the 'read'.
In this particular case, if the uploaded file is ALWAYS a CSV, you can just assume the CSV and start parsing it accordingly. If you expect multiple upload formats, you have to deal with that, for example:
contents = params[:csv_file].read case params[:csv_file].content_type when 'txt/csv' contents.split("\r").each do |csvline| ??? end when 'application/pdf' ??? end