Ruby 通过rake任务将CSV文件上载到Rails 4 DB

Ruby 通过rake任务将CSV文件上载到Rails 4 DB,ruby,csv,ruby-on-rails-4,rake,rails-migrations,Ruby,Csv,Ruby On Rails 4,Rake,Rails Migrations,我试图使用rake任务(rake data:import)从csv fle导入数据,但出现了错误。在过去的几个月里,我一直在自学rails,但在谷歌搜索了一天半之后,我找到了很多解决方案,但没有一个能让我投入工作 这里是我目前使用rake文件的地方: require 'CSV' namespace :data do desc "Import teams from csv file" task :import => [:environment] do file=IO.read

我试图使用rake任务(rake data:import)从csv fle导入数据,但出现了错误。在过去的几个月里,我一直在自学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)>'
tasks/dataimport.rake:7:in'block(2层)in'

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

这里有很多错误,因此我将从顶部开始

是指打开一个文件并一次对其进行迭代。
CSV.foreach
的第一个参数应该是文件名,而不是文件内容。这意味着:

CSV.foreach(file, :headers => true) do |row|
出现错误,因为
file
是包含CSV数据的字符串,而不是
CSV.foreach
所需的文件名。由于您正在从拉丁语-1文本转换为UTF-8,因此需要获取
CSV.foreach
来为您处理该问题,您可以使用
: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 ...
你会得到一个
namererror
,因为在你的rake任务中没有定义
产品。我猜想您的意思是说
Product.create
,这将尝试创建您的
Product
模型的新实例。Ruby是区分大小写的,因此
product
product
是不同的东西,
product
将是类

一旦处理了
名称错误
,您将看到如下投诉:

NoMethodError: undefined method `keys' for [{ ... }]:Array
CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
  Product.create(row.to_hash)
end
您将得到
NoMethodError
,因为
Product.create
希望看到属性及其值的散列,而不是包含散列的数组。你会想说:

Product.create(
  :name => row['name'],
  :rating => row['rating'],
  :year => row['year'],
  :country => row['country'],
  :state_or_province => row['state_or_province']
)
当然,如果
仅包含这五个值,则只需将整个
交给
创建

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

Product.create(row.to_hash.slice(*%w[name rating year country state_or_province]))
请注意,
%w[…]
从以空格分隔的列表中构建字符串数组,因此它们是相同的:

%w[a b]
['a', 'b']
row.to_hash.slice(*%w[name rating year country state_or_province])
row.to_hash.slice('name', 'rating', 'year', 'country', 'state_or_province')
然后splat(
*
)删除数组包装器,使它们相同:

%w[a b]
['a', 'b']
row.to_hash.slice(*%w[name rating year country state_or_province])
row.to_hash.slice('name', 'rating', 'year', 'country', 'state_or_province')
你可以用任何一种更容易看的形式

还要注意里面的电话。您的
将是一个
CSV::row
对象,在其上调用
以_hash
将该行作为hash提供给您


这将使您的整个rake任务如下所示:

NoMethodError: undefined method `keys' for [{ ... }]:Array
CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
  Product.create(row.to_hash)
end


您可能还需要为那些
创建
调用添加一些错误处理。

谢谢!一旦我开始工作,我会把它标记为asnwer。正在尝试找出stringify_keys undefined方法错误。关于
stringify_keys
,您有完整的错误吗?是
产品。创建
抱怨什么吗?非常感谢您的帮助。对于刚接触rails的人来说,这是一个非常用户友好的解释。再次感谢!当我用行中的每个元素替换行时,代码运行良好。完整的错误是未定义方法“stringify_keys”,对,我忘记了
CSV::Row
这件事。你应该能够说
row.to_hash
而不是
row
来处理这个问题。我会更新我的答案。