【问题标题】:Uploading CSV File to Rails 4 DB via rake task通过 rake 任务将 CSV 文件上传到 Rails 4 DB
【发布时间】:2014-02-09 23:52:03
【问题描述】:

我正在尝试使用 rake 任务 (rake data:import) 从 csv 文件导入数据,但出现错误。在过去的几个月里,我一直在自学 Rails,但经过一天半的谷歌搜索,我找到了很多解决方案,但我都无法开始工作。

这是我目前的 rake 文件所在的位置:

require 'CSV'
namespace :data do
  desc "Import teams from csv file"
  task :import => [:environment] do
    file=IO.read('filepath of my csv').force_encoding("ISO-8859-1").encode("utf-8", replace: nil)

    CSV.foreach(file, :headers => true) do |row|
      product.create ([
                       :name => row['name'],
                       :rating => row['rating'],
                       :year => row['year'],
                       :country => row['country'],
                       :state_or_province => row['state_or_province']]
                      )
    end

  end
end

我没有收到任何具体错误(据我所知)。让我困惑的输出是:

tasks/dataimport.rake:7:in `block (2 levels) in <top (required)>'

该输出是否表明发生了什么具体情况?

【问题讨论】:

    标签: ruby csv ruby-on-rails-4 rake rails-migrations


    【解决方案1】:

    这里有很多问题,所以我将从顶部开始。

    CSV.foreach 旨在打开一个文件并一次遍历它。 CSV.foreach 的第一个参数应该是文件name 而不是文件的内容。这意味着:

    CSV.foreach(file, :headers => true) do |row|
    

    出错了,因为 file 是一个包含 CSV 数据的字符串,而不是 CSV.foreach 期望的文件名。由于您要将 Latin-1 文本转换为 UTF-8,因此您需要 CSV.foreach 为您处理该问题,您可以使用 :encoding 选项:

    此方法还理解一个额外的:encoding 参数,您可以使用该参数指定要读取的文件中数据的编码。 [...] 例如,encoding: "UTF-32BE:UTF-8" 会从文件中读取 UTF-32BE 数据,但在 CSV 解析之前将其转码为 UTF-8。

    综合起来,我们有:

    CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
    

    一旦您开始读取 CSV 并进行迭代,您会看到如下错误:

    NameError: undefined local variable or method `product' for ...
    

    你会得到一个NameError,因为在你的 rake 任务的任何地方都没有定义product。我怀疑您的意思是说Product.create,这会尝试创建Product 模型的新实例。 Ruby 区分大小写,所以 productProduct 是不同的东西,Product 是类。

    NameError 处理完毕后,您会看到如下投诉:

    NoMethodError: undefined method `keys' for [{ ... }]:Array
    

    您将获得NoMethodError,因为Product.create 想要查看属性及其值的哈希,而不是包含哈希的数组。你会想说:

    Product.create(
      :name => row['name'],
      :rating => row['rating'],
      :year => row['year'],
      :country => row['country'],
      :state_or_province => row['state_or_province']
    )
    

    当然,如果您的row 只包含这五个值,那么只需将整个row 交给create

    Product.create(row.to_hash)
    

    如果row 包含(或可能包含)一堆您不希望create 看到的其他内容,请使用Hash#slice 获取您感兴趣的row 部分:

    Product.create(row.to_hash.slice(*%w[name rating year country state_or_province]))
    

    请注意,%w[...] 从以空格分隔的列表构建字符串数组,因此它们是相同的:

    %w[a b]
    ['a', 'b']
    

    然后 splat (*) 删除了数组包装器,因此它们是相同的:

    row.to_hash.slice(*%w[name rating year country state_or_province])
    row.to_hash.slice('name', 'rating', 'year', 'country', 'state_or_province')
    

    您可以使用任何一种对您的眼睛更容易的形式。

    还要注意那里的to_hash 调用。您的 row 将是一个 CSV::Row 对象,在其上调用 to_hash 会将您的行作为哈希。


    这应该让你的整个 rake 任务看起来像这样:

    CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
      Product.create(row.to_hash)
    end
    

    CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
      Product.create(row.to_hash.slice(*%w[name rating year country state_or_province]))
    end
    

    您可能还想为这些 create 调用添加一些错误处理。

    【讨论】:

    • 谢谢!一旦我让它工作,我就会把它标记为 asnwer。现在试图找出 stringify_keys 未定义的方法错误。
    • 你有关于stringify_keys的完整错误信息吗?是Product.create在抱怨什么吗?
    • 非常感谢您的帮助。对于刚接触 Rails 的人来说,非常人性化的解释。再次感谢!
    • 当我用行中的每个单独元素替换行时,代码运行良好。完整的错误是 #<:row:0x00000101621a18> 的未定义方法“stringify_keys”
    • 对,我忘了CSV::Row 的事。你应该可以说row.to_hash 而不是row 来处理这个问题。我会更新我的答案。
    猜你喜欢
    • 2012-09-09
    • 1970-01-01
    • 2017-06-21
    • 1970-01-01
    • 2016-09-20
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多