is there a rails method to loop through each line of uploaded file? “each_line” is an IO method but it's not working

匿名 (未验证) 提交于 2019-12-03 09:52:54

问题:

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

回答1:

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!