Ruby 在 Rails - 从不常见格式的 CSV 导入数据

Ruby on Rails - Import Data from uncommon formatted CSV

我有以下格式的 CSV 文件;

Category-1-GUID,Product1
,Product2
,Product3
Category-2-GUID,Product4
,Product5

任务应将以下数据写入模型:

Category-1-GUID,Product1
Category-1-GUID,Product2
Category-1-GUID,Product3
Category-2-GUID,Product4
Category-2-GUID,Product5

我发现 Ruby on Rails - Import Data from a CSV file 对导入数据非常有用,但是这个小差异让我变成了一个笨蛋....

提前致谢!最好的问候

-- 编辑 1:import_productdata.rake 文件:--

desc "Import Product with Category-GUID"
task :import_productdata do
  require 'csv'
    rows = CSV.read('tmp/export1.csv')
    category_id = nil   
    items = rows.map do |row|
    category_id = row[0] unless row[0].nil?
    [category_id, row[1]]
  end
    csv = CSV.parse(items, :headers => false)
    csv.each do |row|
    Product.create!(row.to_hash)
    end
end

错误:

** Invoke import_productdata (first_time)
** Execute import_productdata
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1326:in `ensure in parse': CSV#close at /Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/forwardable.rb:156 forwarding to private method Array#close
rake aborted!
NoMethodError: undefined method `close' for #<Array:0x007fd69f43c3d0>
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/forwardable.rb:226:in `close'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1326:in `ensure in parse'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1326:in `parse'
/Users/bn/Documents/RubyApps/TestApp/lib/tasks/import_productdata.rake:13:in `block in <top (required)>'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:271:in `block in execute'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:271:in `each'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:271:in `execute'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:213:in `block in invoke_with_call_chain'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:193:in `invoke_with_call_chain'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:182:in `invoke'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:160:in `invoke_task'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:116:in `block (2 levels) in top_level'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:116:in `each'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:116:in `block in top_level'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:125:in `run_with_threads'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:110:in `top_level'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:83:in `block in run'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:186:in `standard_exception_handling'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:80:in `run'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/exe/rake:27:in `<top (required)>'
/Users/bn/.rvm/gems/ruby-2.4.0/bin/rake:23:in `load'
/Users/bn/.rvm/gems/ruby-2.4.0/bin/rake:23:in `<main>'

Caused by:
NoMethodError: private method `gets' called for #<Array:0x007fd69f43c3d0>
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1830:in `block in shift'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1828:in `loop'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1828:in `shift'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1770:in `each'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1784:in `to_a'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1784:in `read'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/csv.rb:1324:in `parse'
/Users/bn/Documents/RubyApps/TestApp/lib/tasks/import_productdata.rake:13:in `block in <top (required)>'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:271:in `block in execute'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:271:in `each'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:271:in `execute'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:213:in `block in invoke_with_call_chain'
/Users/bn/.rvm/rubies/ruby-2.4.0/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:193:in `invoke_with_call_chain'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/task.rb:182:in `invoke'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:160:in `invoke_task'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:116:in `block (2 levels) in top_level'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:116:in `each'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:116:in `block in top_level'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:125:in `run_with_threads'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:110:in `top_level'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:83:in `block in run'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:186:in `standard_exception_handling'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/lib/rake/application.rb:80:in `run'
/Users/bn/.rvm/gems/ruby-2.4.0/gems/rake-12.3.1/exe/rake:27:in `<top (required)>'
/Users/bn/.rvm/gems/ruby-2.4.0/bin/rake:23:in `load'
/Users/bn/.rvm/gems/ruby-2.4.0/bin/rake:23:in `<main>'
Tasks: TOP => import_productdata

如果你只调用 CSV.read 那么,

rows = CSV.read('test.csv')

输出为

[["Category-1-GUID", "Product1"], [nil, "Product2"], [nil, "Product3"], ["Category-2-GUID", "Product4"], [nil, "Product5"]]

因此只需将类别 ID 放入 category_id、product_id 对数组。

require 'csv'

rows = CSV.read('test.csv')
category_id = nil

items = rows.map do |row|
  category_id = row[0] unless row[0].nil?
  [category_id, row[1]]
end

p items # [["Category-1-GUID", "Product1"], ["Category-1-GUID", "Product2"], ["Category-1-GUID", "Product3"], ["Category-2-GUID", "Product4"], ["Category-2-GUID", "Product5"]]