Me gustaría importar datos de un archivo CSV a una tabla de base de datos existente. No quiero guardar el archivo CSV, simplemente tomar los datos de ella y la puso en la tabla existente. Estoy usando Ruby 1.9.2 y Rails 3.

Esta es mi tabla:

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 algo de código para que me muestre la mejor manera de hacer esto, gracias.

InformationsquelleAutor freshest | 2010-12-10

11 Comentarios

  1. 362
    require 'csv'    
    
    csv_text = File.read('...')
    csv = CSV.parse(csv_text, :headers => true)
    csv.each do |row|
      Moulding.create!(row.to_hash)
    end
    • ¿Me puedes mostrar donde poner este código, por favor.
    • Usted puede ponerlo en una tarea Rake, o en una acción de controlador, o en cualquier lugar que te gusta….
    • Funcionó a la perfección. Sin embargo tengo un nivel de principiantes pregunta – cuando traté de examinar métodos descritos en Ruby y Rails documentación de la API que no fui capaz de encontrar en su lugar (me miró oficial de Ruby y Rails sitios, la API de google docs). E. g. No pude encontrar el objeto que se devuelve CSV.parse(), no he encontrado to_hash() y with_indifferent_access() métodos… tal vez me veía en el lugar equivocado o ha perdido algunos principio básico sobre cómo recorrer Ruby & Rieles de la API de google docs. ¿Alguien puede compartir las mejores prácticas de cómo leer API Ruby docs?
    • es allí una manera de hacer esto sin tener que cargar el archivo de la memoria?
    • sí, véase mi respuesta a continuación, en el que se lee en el archivo línea a línea.
    • El trabajo para mí… genial!!!!!
    • Si no es un archivo csv, usted puede usar algo como Archivo.open («archivo»).readlines.cada {|línea| clave,valor=línea.split(/[$]/); registro.crear!(clave: clave, valor: valor }
    • me estoy preguntando ¿qué es eso ‘Moduling’ en el código ???
    • se refiere a la OP del modelo.
    • no funciona con las comas en los campos..
    • y para aquellos que reciben el error en la codificación, esto es como me fijo. csv_text = Archivo.leer(‘…’).force_encoding(«UTF-8»)
    • csv = CSV.parse(csv_text, :headers => true, :col_sep => ";") para otro separador.
    • Este método es ineficiente! En la enorme archivos CSV el uso de ram se dispara. la de abajo es la mejor.
    • Que es sin duda cierto. Además, el análisis de archivos muy grandes en Ruby?
    • Sí. Tratando de importar algunas de las grandes CSVs en Activo de Verificación Registro de esta comparación entre todos los métodos. dalibornasevic.com/posts/…
    • Con muchas filas de recibir: hilo de error: inotify de la cola de eventos se ha desbordado

  2. 191

    Versión más simple de yfeldblum la respuesta, que es más simple y también funciona bien con archivos de gran tamaño:

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

    Sin necesidad de with_indifferent_access o symbolize_keys, y no necesita leer el archivo a una cadena de primero.

    No te lo guardes el archivo entero en memoria a la vez, pero lee en línea por línea y crea una Moldeo por línea.

    • Esto es mejor para la gestión de archivos de gran tamaño a la derecha? No lo leí en una línea a la vez?
    • de hecho. No dejes que el archivo entero en memoria a la vez, pero lee en línea por línea y crea una Moldeo por línea.
    • Tengo este error, ¿sabes por qué?: ActiveModel::UnknownAttributeError: atributo desconocido ‘siren;nom_ent;adresse;complement_adresse;cp_ville;pays;region;departement;activite;date;nb_salaries;nom;prenom;civilite;adr_mail;libele_acti;categorie;tel’ para la Transacción
    • Crear una pregunta con su problema. Que el error no está relacionado con esto, el Modelo de objetos parecen estar fuera de sincronización.
    • En este caso, ¿cómo escribir guiones de pruebas para esto?
  3. 10

    La smarter_csv gema fue creado específicamente para este caso de uso: para leer datos de un archivo CSV, y rápidamente crear entradas de 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 utilizar la opción chunk_size leer N csv filas en un momento, y luego usar Resque en el bucle interno para generar puestos de trabajo que creará los nuevos registros, en lugar de crear de inmediato – de esta manera se puede repartir la carga de la generación de entradas a varios trabajadores.

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

    • Como el CSV de la clase está incluido, creo que es mejor usarlo en lugar de añadir o instalar un adicional de gema. Concedido, no proponer una nueva joya ser añadido a la aplicación. Es muy fácil añadir una serie de las piedras individuales, cada uno para un propósito específico y antes de saber que su aplicación tiene un exceso de dependencias. (Me encuentro conscientemente evitar la adición de las gemas. En mi tienda que necesita para justificar la adición a nuestros compañeros de equipo.)
    • Funciona! Gracias!
    • es muy fácil añadir una serie de métodos individuales, cada uno para un propósito específico y antes de saber que su aplicación tiene un exceso de lógica que usted tiene que mantener. Si una gema funciona, está bien mantenido, y utiliza pocos recursos o puede ser puesto en cuarentena a los ámbitos pertinentes (es decir, de Ensayo para tareas de producción) a mí me parece que siempre una mejor opción a utilizar la joya. Ruby y Rails son todos acerca de cómo escribir menos código.
    • Tengo el siguiente error, ¿sabes por qué? ActiveModel::UnknownAttributeError: atributo desconocido ‘siren;nom_ent;adresse;complement_adresse;cp_ville;pays;region;departement;activite;date;nb_salaries;nom;prenom;civilite;adr_mail;libele_acti;categorie;tel’ para la Transacción
    • He probado esto en una tarea rake, consola devuelve: el rake abortado! NoMethodError: undefined method `cerrar’ para nil:NilClass stackoverflow.com/questions/42515043/…
    • se parece a alguien ya le respondió – solo prefijo de su archivo CSV ubicación con ./
    • chunking el CSV de procesamiento, mejorar la velocidad y el ahorro de la memoria podría ser una buena justificación para añadir una nueva joya 😉

  4. 4

    Usted puede tratar de 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 usted desea, usted también podría considerar la posibilidad de deshacerse de la auto-incremento de la clave principal de la tabla y la configuración de la clave principal para name. Alternativamente, si hay alguna combinación de atributos que forman la clave principal, el uso de que como el selector. No hay ningún índice es necesario, que se acaba de hacer más rápido.

  5. 2

    Es mejor para envolver la base de datos relacionados con el proceso dentro de un transaction bloque. Fragmento de código de soplado es un proceso de siembra de un conjunto de idiomas para el modelo de Lenguaje,

    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

    Siguiente fragmento es un parcial de languages.csv archivo,

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

    La mejor forma es incluir en una tarea de rake. Crear la importación.rastrillo de archivo dentro de /lib/tasks/y poner este código para 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 que se ejecute este comando en tu terminal rake csv_model_import[file.csv,Name_of_the_Model]

  7. 0

    Sé que es una pregunta vieja, pero todavía en el primer 10 enlaces en google.

    No es muy eficiente para guardar filas, uno por uno, porque es la causa de base de datos llamada en el bucle y lo mejor es evitar que, especialmente cuando usted necesita para insertar una enorme cantidad de datos.

    Es mejor (y significativamente más rápido) para utilizar lote insertar.

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

    Puede crear una consulta de forma manual y que Model.connection.execute(RAW SQL STRING) (no recomendado)
    o el uso de la gema activerecord-import (fue lanzado por primera vez el 11 de Agosto de 2010) en este caso sólo tienes que poner los datos en la matriz de rows y llame a Model.import rows

    consulte joya docs para más detalles

  8. -2

    Es mejor usar CSV::la Tabla y el uso String.encode(universal_newline: true). Es la conversión de CRLF y CR a LF

    • ¿Cuál es la solución que usted propone?
  9. -3

    Si quieres Usar SmartCSV

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

    Esto representa delimitado por tabulaciones de datos en cada fila "\t" con filas separadas por líneas nuevas "\n"

Dejar respuesta

Please enter your comment!
Please enter your name here