Using Ruby CSV header converters

10,226

Solution 1

After doing some research here in my desktop, it seems to me the error is for something else.

First I put the data in my "a.txt" file as below :

First Name,Last Name
John,Doe
Jane,Doe

Now I ran the code, which is saved in my so.rb file.

so.rb

require 'csv'

CSV.foreach("C:\\Users\\arup\\a.txt", 
             :headers => true,
             :converters => :all,
             :header_converters => lambda { |h| h.downcase.gsub(' ', '_') }
           ) do |row|
    p row
end

Now running the :

C:\Users\arup>ruby -v so.rb
ruby 1.9.3p448 (2013-06-27) [i386-mingw32]
#<CSV::Row "first_name":"John" "last_name":"Doe">
#<CSV::Row "first_name":"Jane" "last_name":"Doe">

So everything is working now. Now let me reproduce the error :

I put the data in my "a.txt" file as below ( just added a , after the last column) :

First Name,Last Name,
John,Doe
Jane,Doe

Now I ran the code, which is saved in my so.rb file, again.

C:\Users\arup>ruby -v so.rb
ruby 1.9.3p448 (2013-06-27) [i386-mingw32]
so.rb:5:in `block in <main>': undefined method `downcase' for nil:NilClass (NoMethodError)

It seems, in your header row, there is blank column value which is causing the error. Thus if you have a control to the source CSV file, check there the same. Or do some change in your code, to handle the error as below :

require 'csv'

CSV.foreach("C:\\Users\\arup\\a.txt",
             :headers => true,
             :converters => :all,
             :header_converters => lambda { |h| h.downcase.gsub(' ', '_') unless h.nil? }
           ) do |row|
    p row
end

Solution 2

A more general answer, but if you have code that you need to process as text, and sometimes you might get a nil in there, then call to_s on the object. This will turn nil into an empty string. eg

h.to_s.downcase.gsub(' ', '_') 

This will never blow up, whatever h is, because every class in ruby has the to_s method, and it always returns a string (unless you've overridden it to do something else, which would be unadvisable).

Share:
10,226
jcm
Author by

jcm

Updated on July 28, 2022

Comments

  • jcm
    jcm almost 2 years

    Say I have the following class:

    class Buyer < ActiveRecord::Base
      attr_accesible :first_name, :last_name
    

    and the following in a CSV file:

    First Name,Last Name
    John,Doe
    Jane,Doe
    

    I want to save the contents of the CSV into the database. I have the following in a Rake file:

    namespace :migration do
      desc "Migrate CSV data"
      task :import, [:model, :file_path] => :environment do |t, args|
        require 'csv'
    
        model = args.model.constantize
        path = args.file_path
        CSV.foreach(path, :headers => true,
                          :converters => :all,
                          :header_converters => lambda { |h| h.downcase.gsub(' ', '_') }
                          ) do |row|
        model.create!(row.to_hash)
      end
    end
    

    end

    I am getting an undefined method 'downcase' for nil:NilClass. If I exclude the header converters then I get unknown attribute 'First Name'. What's the correct syntax for converting a header from, say, First Name to first_name?

  • jcm
    jcm about 10 years
    You're right, there was an extra comma somewhere, but the strange thing is, the code still needs your initial suggestion of :return_headers => true to work. Otherwise it gives an undefined attribute: error.
  • Arup Rakshit
    Arup Rakshit about 10 years
    @jcm Then do add that, but without :return_headers => true, the code ran as expected here for me.