2013-04-01 4 views
3

У меня есть загруженный CSV-файл, который я анализирую, как так:Рубин - Вставка записей из CSV в базу данных

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

Поступающий CSV файл имеет, по меньшей мере, следующие столбцы: «имя» «идентификатор», «число», «телефон» и «еда».

Я хотел бы сделать что-то вроде:

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 

Обратите внимание, что файл CSV всегда будут иметь имена столбцов в первой строке, однако из файла в файл, упорядочение этих столбцов может отличаться.

+0

Вам нужна первая строка в файле CSV, чтобы назвать столбцы, иначе как вы можете обрабатывать записи? – Raffaele

+0

В первой строке есть имена столбцов, однако порядок столбцов может отличаться от файла к файлу – CodeGuy

ответ

8

Вот фрагмент кода, который будет собирать только те поля, которые вас интересуют в массив хэш:

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 

Учитывая следующее содержание 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 будет содержат:

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

я бы это и использовать activerecord-import, чтобы вставить их все сразу:

SomeModel.import(rows_to_insert) 

Вы можете вставить записей, по одному в цикле CSV, но это неэффективно, и потому id, как правило, защищенный атрибут , вы не можете массового назначения, поэтому вы должны сделать это, чтобы вставить одну запись:

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

... или что-то подобное.

+3

Попробуйте 'row.to_hash.values_at (* fields_to_insert)' вместо 'row.to_hash.select {| k, v | fields_to_insert.include? (k)} '. –

3

Если первая строка является именами заголовков, вы можете использовать опцию :headers => true для parse, чтобы использовать первую строку в качестве ключей для данных.

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 
+0

Используйте CSV.foreach вместо File.read + CSV.parse – pguardiario

Смежные вопросы