rails ruby-on-rails csv import

ruby-on-rails - rails import bulk



Ruby on Rails-Importar datos de un archivo CSV (11)

Me gustaría importar datos desde un archivo CSV a una tabla de base de datos existente. No quiero guardar el archivo CSV, solo tomar los datos de él y ponerlo en la tabla existente. Estoy usando Ruby 1.9.2 y Rails 3.

Esta es mi mesa:

create_table "mouldings", :force => true do |t| t.string "suppliers_code" t.datetime "created_at" t.datetime "updated_at" t.string "name" t.integer "supplier_id" t.decimal "length", :precision => 3, :scale => 2 t.decimal "cost", :precision => 4, :scale => 2 t.integer "width" t.integer "depth" end

¿Me puede dar algún código para mostrarme la mejor manera de hacerlo, gracias?


Es mejor ajustar el proceso relacionado con la base de datos dentro de un bloque de transaction . El fragmento de código soplo es un proceso completo de sembrar un conjunto de idiomas para el modelo de idioma,

require ''csv'' namespace :lan do desc ''Seed initial languages data with language & code'' task init_data: :environment do puts ''>>> Initializing Languages Data Table'' ActiveRecord::Base.transaction do csv_path = File.expand_path(''languages.csv'', File.dirname(__FILE__)) csv_str = File.read(csv_path) csv = CSV.new(csv_str).to_a csv.each do |lan_set| lan_code = lan_set[0] lan_str = lan_set[1] Language.create!(language: lan_str, code: lan_code) print ''.'' end end puts '''' puts ''>>> Languages Database Table Initialization Completed'' end end

El fragmento a continuación es un archivo parcial de languages.csv ,

aa,Afar ab,Abkhazian af,Afrikaans ak,Akan am,Amharic ar,Arabic as,Assamese ay,Aymara az,Azerbaijani ba,Bashkir ...


Es mejor usar CSV :: Table y usar String.encode(universal_newline: true) . Convierte CRLF y CR a LF



La gema smarter_csv se creó específicamente para este caso de uso: para leer datos del archivo CSV y crear rápidamente entradas de la base de datos.

require ''smarter_csv'' options = {} SmarterCSV.process(''input_file.csv'', options) do |chunk| chunk.each do |data_hash| Moulding.create!( data_hash ) end end

Puede usar la opción chunk_size para leer N csv-rows a la vez, y luego usar Resque en el bucle interno para generar trabajos que crearán los nuevos registros, en lugar de crearlos de inmediato, de esta forma puede distribuir la carga de generación entradas a múltiples trabajadores.

Ver también: https://github.com/tilo/smarter_csv


La mejor manera es incluirlo en una tarea de rake. Cree el archivo import.rake dentro de / lib / tasks / y coloque este código en ese archivo.

desc "Imports a CSV file into an ActiveRecord table" task :csv_model_import, [:filename, :model] => [:environment] do |task,args| lines = File.new(args[:filename], "r:ISO-8859-1").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

Después de eso, ejecute este comando en su rake csv_model_import[file.csv,Name_of_the_Model] terminal rake csv_model_import[file.csv,Name_of_the_Model]


Puede probar Upsert :

require ''upsert'' # add this to your Gemfile require ''csv'' u = Upsert.new Moulding.connection, Moulding.table_name CSV.foreach(file, headers: true) do |row| selector = { name: row[''name''] } # this treats "name" as the primary key and prevents the creation of duplicates by name setter = row.to_hash u.row selector, setter end

Si esto es lo que desea, también puede considerar deshacerse de la clave primaria de incremento automático de la tabla y configurar la clave principal para el name . Alternativamente, si hay alguna combinación de atributos que forman una clave principal, utilícela como selector. No es necesario ningún índice, solo lo hará más rápido.


Sé que es una pregunta antigua, pero sigue en los primeros 10 enlaces en google.

No es muy eficiente guardar filas una por una porque causa una llamada a la base de datos en el ciclo y será mejor que lo evite, especialmente cuando necesite insertar grandes porciones de datos.

Es mejor (y significativamente más rápido) usar la inserción por lotes.

INSERT INTO `mouldings` (suppliers_code, name, cost) VALUES (''s1'', ''supplier1'', 1.111), (''s2'', ''supplier2'', ''2.222'')

Puede crear una consulta de este tipo de forma manual y hacer Model.connection.execute(RAW SQL STRING) (no recomendado) o usar gem activerecord-import (se lanzó por primera vez el 11 de agosto de 2010) en este caso simplemente coloque datos en rows matriz y llame a Model.import rows

consulte los documentos de gemas para más detalles


Si quieres usar SmartCSV

all_data = SmarterCSV.process( params[:file].tempfile, { :col_sep => "/t", :row_sep => "/n" } )

Esto representa datos delimitados por tabulaciones en cada fila "/t" con filas separadas por nuevas líneas "/n"


Una versión más simple de la respuesta de yfeldblum, que es más simple y funciona bien también con archivos grandes:

require ''csv'' CSV.foreach(filename, :headers => true) do |row| Moulding.create!(row.to_hash) end

No es necesario usar with_indifferent_access o symbolize_keys, y no es necesario leer primero el archivo en una cadena.

No mantiene todo el archivo en la memoria a la vez, pero lee en línea por línea y crea un Molding por línea.


Utilice esta joya: https://rubygems.org/gems/active_record_importer

class Moulding < ActiveRecord::Base acts_as_importable end

Entonces ahora puedes usar:

Moulding.import!(file: File.open(PATH_TO_FILE))

Solo asegúrate de que tus encabezados coincidan con los nombres de columna de tu tabla


require ''csv'' csv_text = File.read(''...'') csv = CSV.parse(csv_text, :headers => true) csv.each do |row| Moulding.create!(row.to_hash) end