2014-10-30 94 views
2

我试图使用Roo gem基于http://railscasts.com/episodes/396-importing-csv-and-excel将CSV和Excel文件导入到rails 4项目(带验证)中。Roo with rails4给出了未定义的方法`[]'为零:NilClass

我已经做了一些改动,以考虑Rails4代替Rails3中和改变小豆,我ProjectImporter模型现在看起来像:

class ProductImport 
    include ActiveModel::Model 
    attr_accessor :file 

    def initialize(attributes = {}) 
    attributes.each { |name, value| send("#{name}=", value) } 
    end 

    def persisted? 
    false 
    end 

    def save 
    if imported_products.map(&:valid?).all? 
     imported_products.each(&:save!) 
     true 
    else 
     imported_products.each_with_index do |product, index| 
     product.errors.full_messages.each do |message| 
      errors.add :base, "Row #{index + 2}: #{message}" 
     end 
     end 
     false 
    end 
    end 

    def imported_products 
    @imported_products ||= load_imported_products 
    end 

    def load_imported_products 
    spreadsheet = open_spreadsheet 
    spreadsheet.default_sheet = spreadsheet.sheets.first 
    puts "!!! Spreadsheet: #{spreadsheet}" 
    header = spreadsheet.row(1) 
    (2..spreadsheet.last_row).map do |i| 
     row = Hash[[header, spreadsheet.row(i)].transpose] 
     product = Product.find_by(id: row['id']) || Product.new 
     product.attributes = row.to_hash.slice(*['name', 'released_on', 'price']) 
     product 
    end 
    end 

    def open_spreadsheet 
    case File.extname(file.original_filename) 
     when ".csv" then 
     Roo::CSV.new(file.path, nil) 
     when '.tsv' then 
     Roo::CSV.new(file.path, csv_options: { col_sep: "\t" }) 
     when '.xls' then 
     Roo::Excel.new(file.path, nil, :ignore) 
     when '.xlsx' then 
     Roo::Excelx.new(file.path, nil, :ignore) 
     when '.ods' then 
     Roo::OpenOffice.new(file.path, nil, :ignore) 
     else 
     raise "Unknown file type #{file.original_filename}" 
    end 
    end 
end 

当我尝试运行导入(使用测试CSV数据),它在header = spreadsheet.row(1)上失败,错误号为undefined method '[]' for nil:NilClass。我列出的额外puts声明确认spreadsheet本身不是零:它给出!!! Spreadsheet: #<Roo::CSV:0x44c2c98>。但是,如果我尝试调用几乎所有的预期方法,例如#last_row,它会给我提供相同的未定义方法错误。

那么我做错了什么?

+1

它可能告诉你到底发生了什么行'NilClass'错误。请提供。 – deefour 2014-10-30 16:33:59

+0

我已经提供了。正如我写的,“它在'header = spreadsheet.row(1)'”上失败。这是'load_imported_products'的第4行,在插入调试'puts'后立即检查'spreadsheet'不是'nil'。 – digitig 2014-11-04 09:15:56

+1

'.row(1)'不是方法'[]'。发生错误时,我要求提供完整的调用堆栈。 '[]'可能来自Roo内部 - 您应该在调用堆栈中看到一行引用该行。 '.row(1)'就是您所做的失败的API调用,会触发错误。 – deefour 2014-11-04 13:10:34

回答

7

我有同样的问题,它似乎是一个关于文件enconding的问题,我用这个代码,它是固定的。

def open_spreadsheet 
    case File.extname(file.original_filename) 
     when ".csv" then Roo::CSV.new(file.path, csv_options: {encoding: "iso-8859-1:utf-8"}) 
     when ".xls" then Roo::Excel.new(file.path, nil, :ignore) 
     when ".xlsx" then Roo::Excelx.new(file.path, nil, :ignore) 
     else raise "Unknown file type: #{file.original_filename}"   
    end 
end 

我希望对你有帮助。

+0

在指定之前,什么是默认编码? – jayant 2016-05-05 08:46:11

+0

另外,谢谢! :) – jayant 2016-05-05 09:01:13

相关问题