2

我正在尝试上传一个 csv 文件,对其进行解析,然后为 S3 吐出一个文件,或者只是传递给查看。我使用 file_field_tag 上传 csv。我认为 file_field_tag 传递了一个作为 IO 子类的对象,并且将具有所有 ruby​​ IO 方法,例如“each_line”。我可以在对象(IO 类的方法)上调用“读取”,但不能调用“each_line”......那么如何遍历 file_field_tag 上传的每一行?

我的控制器的创建方法为:

@csv_file = params[:csv_file]

我的显示视图引发了 no "each_line" 方法错误:

<% @csv_file.each_line do |line| %>
<%= line %>
<% end %>

然而我可以使用

<%= @csv_file.read(100) %>

我真的很困惑 file_field_tag 上传参数 [] 有什么方法......每个行,都不起作用......我似乎找不到我可以使用的列表。

编辑 我通过以下方式解决了这个问题:

@csv_file = params[:csv_file].read.to_s

然后迭代:

<% @sp_file.each_line do |line| %>
<%= line %>
<% end %>

编辑2 正在上传的文件在不包含逗号的行之后重复了标题(不要问)......所以我找到没有逗号的行并调用.gets(在我的rb脚本中独立于rails)。不幸的是,我收到了一个关于 gets 是我不能调用的私有方法的错误。这可以追溯到我最初的问题。文件不是 IO 的子类,具有 read_lines 和 get 等 IO 方法吗?

        @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
4

1 回答 1

2

当您发布 'file_field' 时,返回给控制器的参数有一些特殊的魔法。

即在你的情况下你可以这个

<%= "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}" %>

所以这些是您可以在 params[:csv_file] 上调用的三种特殊方法,或者作为视图中成功的 'file_field_tag' 或 'f.file_field' 的结果发布的任何参数

请记住,这些是您可以对作为 file_field 的结果发布的参数进行的三个额外的特殊操作:

original_filename

内容类型

您已经清楚地知道如何进行读取,original_filename 和 content_type 将来可能会帮助您。

编辑

好的,所以你只有 read 方法,它将读取上传文件的内容。

contents = params[:csv_file].read

所以现在 contents 是一个包含文件内容的字符串,但除了它是一个 csv 文件外,对该文件一无所知。我们知道 csv 用 '\r' 分隔(我想,我在解析 csv 方面做了很多工作,但我懒得去检查)

所以你可以这样做:

contents = params[:csv_file].read
contents.split("\r").each do |csvline|
  ???
end

编辑 2

所以这是这篇文章的要点

当您将 file_field 发布到控制器时,与上传文件的内容有关的最常见的事情是将其“读取”到 ruby​​ 字符串中。上传内容的任何额外处理都必须在从“读取”返回的 ruby​​ 字符串上完成。

在这种特殊情况下,如果上传的文件始终是 CSV,您可以假设 CSV 并相应地开始解析它。如果您期望多种上传格式,则必须处理它,例如:

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
于 2013-01-06T02:38:39.123 回答