4 votes

Ruby - Insertion d'entrées depuis un CSV dans une base de données

J'ai un fichier CSV téléchargé, que j'analyse comme suit :

CSV.foreach(@my_file.file.path) do |row|
    puts row[1]
end

Le fichier CSV entrant comporte au moins les colonnes suivantes : "id", "name", "number", "phone", et "food".

Je voudrais faire quelque chose comme :

CSV.foreach(@my_file.file.path) do |row|
     //find the columns in "row" associated with "id", "name", "number"
     //even though I don't know definitively which column they will be in
     //for example, "name" may be the 2nd or 3rd or 4th column (etc)

     //insert into my_table values(id, name, number)

end

Notez que le fichier CSV aura toujours les noms des colonnes comme première ligne, cependant d'un fichier à l'autre, l'ordre de ces colonnes peut différer.

9voto

Jim Stewart Points 6811

Voici un extrait de code qui rassemblera uniquement les champs qui vous intéressent dans un tableau de hachages :

require 'csv'

fields_to_insert = %w{ id name food number phone }
rows_to_insert = []

CSV.foreach("stuff.csv", headers: true) do |row|
  row_to_insert = row.to_hash.select { |k, v| fields_to_insert.include?(k) }
  rows_to_insert << row_to_insert
end

Étant donné le contenu suivant de stuff.csv :

junk1,name,junk2,food,id,junk4,number,phone
foo,Jim,bar,pizza,123,baz,9,555-1212
baz,Fred,bar,sushi,55,foo,44,555-1213

rows_to_insert contiendra :

[{"name"=>"Jim",
  "food"=>"pizza",
  "id"=>"123",
  "number"=>"9",
  "phone"=>"555-1212"},
 {"name"=>"Fred",
  "food"=>"sushi",
  "id"=>"55",
  "number"=>"44",
  "phone"=>"555-1213"}]

Je prendrais ça et j'utiliserais activer l'enregistrement-importation pour les insérer tous en même temps :

SomeModel.import(rows_to_insert)

Vous pourriez insérer les enregistrements un par un dans la boucle CSV, mais cela est inefficace, et parce que id est normalement un attribut protégé, vous ne pouvez pas l'attribuer en masse. Vous devez donc procéder ainsi pour insérer un seul enregistrement :

some_model = SomeModel.new(row_to_insert.select { |k, v| k != "id" }
some_model.id = row_to_insert["id"]
some_model.save!

...ou quelque chose de similaire.

3voto

Richard Brown Points 7716

Si la première ligne est constituée des noms d'en-tête, vous pouvez utiliser la fonction :headers => true option pour parse afin d'utiliser la première ligne comme clé pour les données.

text = File.read(@my_file.file.path)
csv = CSV.parse(text, :headers => true)
csv.each do |row|
  row = row.to_hash.with_indifferent_access
  YourModel.create!(row.to_hash.symbolize_keys)
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X