【问题标题】:Rails - Can't import data from CSV fileRails - 无法从 CSV 文件导入数据
【发布时间】:2016-08-14 08:34:54
【问题描述】:

我正在尝试从 CSV 文件导入数据,我不想保存该文件。我在这里发现了一个类似的问题:Ruby on Rails - Import Data from a CSV file

但是,当我尝试使用此解决方案时,出现错误。

我的表格如下:

Import a CSV file
<%= file_field_tag :file %>

<div class="actions form-group" id="button_text">
<p>
<%= button_tag(type: 'submit', class: "btn btn-primary button-submit") do %>
Submit
<% end %>

在新页面上这个表单的提交调用创建动作,创建动作然后调用行:

Product.import(params[:file])

我的模型中有以下导入方法:

def self.import(myfile)
    require 'csv'    

    csv_text = File.read(myfile)
    csv = CSV.parse(csv_text, :headers => true)
    csv.each do |row|

    end
end

其中 'myfile' 是 params[:file]。

我知道我还没有对数据做任何事情。我收到csv_text = File.read(myfile) 行的错误,即:没有这样的文件或目录@rb_sysopen - X.csv

在寻找解决方案时,我看到使用了 .path。如果我将此行更改为 csv_text = File.read(myfile.path) 我会收到错误:未定义的方法 `path' for "X.csv":String

有人可以帮忙吗?我觉得我必须非常接近解决方案,但我只是在这两个错误之间不停地转来转去。是否可以在不先保存的情况下从 csv 中获取数据?

感谢您的宝贵时间

【问题讨论】:

    标签: ruby-on-rails csv import


    【解决方案1】:

    你可以这样做 .html.erb

    <%= form_for(<object>, url: <path>, method: :post, remote: :true, html: {
      multipart: true, }) do |f| %>
        <input type="file" name="file_batch_upload"  accept=".csv />
    <% end %>
    

    //定义那个函数

    def self.import(file)
        require 'csv'    
    
        csv_text = File.read(file.tempfile)
        csv = CSV.parse(csv_text, :headers => true)
        csv.each do |row|
         //row["name"]
        end
    end
    

    【讨论】:

    • 抱歉,您能解释一下吗?我无法让它工作,.tempfile 未定义为字符串的文件
    【解决方案2】:

    文件上传要记住的最重要的事情是渲染表单的编码必须设置为multipart/form-data。我猜你已经保留了它。

    <%= form_tag({action: :upload}, multipart: true) do %>
      <%= file_field_tag 'file' %>
    <% end %>
    

    现在在控制器中,您将可以通过params 访问IO 对象。 params 散列中的对象是 IO 子类的一个实例。

    该对象将具有一个 original_filename 属性,其中包含文件在用户计算机上的名称,以及一个 content_type 属性,其中包含上传文件的 MIME 类型。

    您可以将临时文件移动到您的public 目录中的某个目录,或者简单地使用并丢弃。

    def upload
      uploaded_io = params[:file]
    
      # Moving the file to some safe place; as tmp files will be flushed timely
      File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'wb') do |file|
        file.write(uploaded_io.read)
      end
    end
    

    您可以利用IO 对象中的tempfile 属性。实际文件可通过 tempfile 访问器访问,但为方便起见,它的某些接口可直接使用。

    所以,这应该可以工作

    ...
    csv_text = File.read(file.tempfile)
    ...
    

    更新

    > uploaded_io = params[:file]
    => #<ActionDispatch::Http::UploadedFile:0x007f4154fe9a38
     @content_type="application/pdf",
     @headers="Content-Disposition: form-data; name=\"file\"; filename=\"3423loadshedding.pdf\"\r\nContent-Type: application/pdf\r\n",
     @original_filename="3423loadshedding.pdf",
     @tempfile=#<File:/tmp/RackMultipart20160421-14883-1lv0qtq.pdf>>
    
    [2] pry(#<PostsController>)> uploaded_io.tempfile
    => #<File:/tmp/RackMultipart20160421-14883-1lv0qtq.pdf>
    
    > uploaded_io.tempfile.class
    => Tempfile
    

    错误

    ProductsController#upload No such file or directory @ rb_sysopen - /<path to my app>/public/uploads/X.csv 
    

    你需要先创建文件夹public/uploads

    $ mkdir public/uploads
    

    现在试试;该文件应该被移动。这就是PaperclipCarrierwave 管理上传文件的方式。

    【讨论】:

    • 抱歉这个愚蠢的问题.. 我收到错误: ProductsController#upload 中的 Errno::ENOENT 没有这样的文件或目录 @ rb_sysopen - //public/uploads/X .csv 当你说我可以将临时文件移动到我的公共目录中的一个目录时,你的意思是手动吗?程序里有没有办法做到这一点?
    • 我想我可能有它与 upload_io = params[:file].tempfile csv_text = File.read(uploaded_io) 但需要正确测试
    猜你喜欢
    • 2011-05-23
    • 2020-04-26
    • 2011-11-29
    • 2014-01-27
    • 2015-06-30
    • 2017-05-03
    • 1970-01-01
    相关资源
    最近更新 更多