这里有很多问题,所以我将从顶部开始。
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 区分大小写,所以 product 和 Product 是不同的东西,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 调用添加一些错误处理。