akaras222
akaras222

Reputation: 81

Ruby on Rails CSV Import rake task Fails Silently and does not import data

I have tried to import a CSV file into ruby on rails using many scripts and methods and nothing seems to work. I have been hoping that code from Erik on Rails blog will help to get my job done.

I put this script into lib/tasks/import.rake:

desc "Imports a CSV file into an ActiveRecord table"
task :csv_model_import, [:filename, :model, :needs] => [:environment] do |task,args|
  lines = File.new(args[:filename]).readlines
  header = lines.shift.strip
  keys = header.split(',')
  lines.each do |line|
    values = line.strip.split(',')
    attributes = Hash[keys.zip values]
    Module.const_get(args[:model]).create(attributes)
  end
end

I created a model in the rails console

rails generate model SomeModel

then ran this in the rails console

rake csv_model_import[somefile.csv,SomeModel]

After running this, the cursor just returns in the console. It fails silently. When viewing the database file for the rails program, the table is empty after the import. It has filed to import the data.

I tried something else as well. I tried first creating a model with the fields and types defined before running the rake import command. This also failed in the same way.

I am very new to Ruby on Rails and I am. I have spent 2 days trying to get a CSV file into Ruby on Rails and would greatly appreciate some help. Please let me know how to proceed, Thanks so much guys.

Upvotes: 0

Views: 362

Answers (1)

x6iae
x6iae

Reputation: 4164

Following on your approach and why you may not be getting anything:

When I tried to replicate the error, the following is what I found out:

the line lines = File.new(args[:filename]).readlines reads the file in as one element separated by commas(,) for cells and new lines (\r or \n) for new lines... e.g: ["name,age,food\rtabitha,2,carrots\relijah,1,lettuce\rbeatrice,3,apples"]

This is the major problem because the blog post probably had another format gotten, on which the rest of the code is based on.

With this output, however... performing the shifting and splitting and stripping as above yields no result.

What I then did was to work off based on the result with the following steps:

1) Get the content:

file = File.new(args[:filename]).readlines => ["name,age,food\rtabitha,2,carrots\relijah,1,lettuce\rbeatrice,3,apples"]

2) Parse into a desired format by splitting on the new-lines (\r in my case)

lines = file.shift.strip.gsub(/\r/,"\\").split(/\\/) => ["name,age,food", "tabitha,2,carrots", "elijah,1,lettuce", "beatrice,3,apples"]

3) Get the headers:

header = lines.first => "name,age,food"

4) Get the body:

body = lines[1..-1] => ["tabitha,2,carrots", "elijah,1,lettuce", "beatrice,3,apples"]

5) Get keys from header:

keys = header.split(',') => ["name", "age", "food"]

6) Loop through the body and create objects in the database:

body.each do |line|
  values = line.strip.split(',')
  attributes = Hash[keys.zip values]
  Module.const_get(args[:model]).create(attributes)
end

The full gist is as follow:

desc "Imports a CSV file into an ActiveRecord table"
task :csv_model_import, [:filename, :model, :needs] => [:environment] do |task,args|
  file = File.new(args[:filename]).readlines
  lines = file.shift.strip.gsub(/\r/,"\\").split(/\\/)
  header = lines.first
  body = lines[1..-1]
  keys = header.split(',')
  body.each do |line|
    values = line.strip.split(',')
    attributes = Hash[keys.zip values]
    Module.const_get(args[:model]).create(attributes)
  end
end

PS: I notice the comment on ProgNoob's answer. you have to create a model first with all the needed attributes and have the database migrated. Then you can pass the model name and the csv file name into the rake file.

In my case, I have a model Somemodel generated as follow:

rails g model somemodel name:string age:string food:string

Notice that I added all the desired attributes.

And then migrated my database as:

$ rake db:migrate

Upvotes: 1

Related Questions