0

I'm running Rails 5.2 on Windows. I followed advice from @Tom De Leu (Ruby on Rails - Import Data from a CSV file) to import CSV data into a table as follows:

task :import_currencies => :environment do

    require 'csv'

    filename = File.join Rails.root, "lib/tasks/forex20sep2018.csv"
    CSV.foreach(filename, :headers => true) do |row|
      Currency.create!(row.to_hash)
    end

end

The CSV itself looks like this:

code,name,symbol
AED,UAE Dirham,د.إ
ALL,Lek,Lek
AMD,Armenian Dram,Lek
ANG,Netherlands Antillean Guilder,ƒ
...

but when I run the rake task:

rails import_currencies

it fails with this error:

rails aborted!
ActiveModel::UnknownAttributeError: unknown attribute 'code' for Currency.

So I modified my code as follows:

task :import_currencies => :environment do

    require 'csv'

    filename = File.join Rails.root, "lib/tasks/forex20sep2018.csv"
    CSV.foreach(filename, :headers => true) do |row|
        c = Currency.new
        c.code = row[0]
        c.name = row[1]
        c.symbol = row[2]
        c.save
        puts c.errors.full_messages
    end

end

And this runs perfectly well. The trouble is it's neither flexible nor elegant so I'd like to know why the original code didn't work.

(FWIW, I tried changing the CSV header as follows:

'code', 'name', 'symbol'
"code", "name", "symbol"
:code, :name, :symbol

None of these helped at all.)

@Vishal asked for the table:

create_table "currencies", force: :cascade do |t|
  t.string "name"
  t.string "code"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.string "symbol"
  t.index ["code"], name: "index_currencies_on_code"
end

After as few suggestions, I have just made a dummy CSV with one record:

code,name,symbol
AAA,Dollar,$

and running this code:

task :import_currencies_org => :environment do

    require 'csv'    

    filename = File.join Rails.root, "lib/tasks/forex20sep2018dummy.csv"
    CSV.foreach(filename, :headers => true) do |row|
      puts row.to_hash
      Currency.create!(row.to_hash)
    end

end

... still get this error:

enter image description here

MSC
  • 3,286
  • 5
  • 29
  • 47
  • Add the table of currencies in question – Vishal Sep 20 '18 at 03:10
  • Insert a byebug line (or your equivalent debugger) just above this line `Currency.create!(row.to_hash)` and report what the row.to_hash is returning. – BenKoshy Sep 20 '18 at 03:33
  • @BKSpurgeon it returns {"code"=>"AED", "forex"=>"3.6727", "name"=>"UAE Dirham", "symbol"=>"د.إ"}. When I paste this into a console, the Arabic seems to mess up and produce question marks so I get an error when trying to create from the console with it: c= Currency.new({"?code"=>"AED", "name"=>"UAE Dirham", "symbol"=>"?.?"}). ActiveModel::UnknownAttributeError: unknown attribute '?code' for Currency. I think that's more a problem with my ConEmu command line than anything else. If I just insert "puts row.to_hash" before Create!, I get a tidy looking hash. – MSC Sep 20 '18 at 03:46
  • So probably not what you want to hear, just setup this in a fresh 5.2 on Mac system and all worked. There is a good chance you are pushing up against a bug on the platform. – Austio Sep 20 '18 at 03:48
  • @MSC then you gotta clean the row.to_hash output so that it will return a hash acceptable to active_record, or, as you have done above: manually set the value of the relevant keys to the active record model attributes. a simple regex to remove all sorts of `?` marks should solve it. because this type of thing: ` c.code = row[0]` can get annoying if someone changes the column order of the csv. – BenKoshy Sep 20 '18 at 03:54
  • If I take out the Arabic and shorten the CSV to just one record, I still get the same error. I will add to the OP. – MSC Sep 20 '18 at 04:02
  • @MSC the only other thing i can think of - it could be an encoding issue re: CSV (try UTF8 or a format that active record is expecting). – BenKoshy Sep 20 '18 at 04:32
  • Thanks, @BKSpurgeon. I thought that too but it's already UTF8 all the way through. – MSC Sep 20 '18 at 04:34

0 Answers0