ruby-on-rails - ruby load csv




Ruby on Rails: importa i dati da un file CSV (8)

Vorrei importare i dati da un file CSV in una tabella di database esistente. Non voglio salvare il file CSV, basta prendere i dati da esso e metterlo nella tabella esistente. Sto usando Ruby 1.9.2 e Rails 3.

Questa è la mia tabella:

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

Puoi darmi un codice per mostrarmi il modo migliore per farlo, grazie.


È meglio racchiudere il processo relativo al database all'interno di un blocco di transaction . Lo snippet blow del codice è un processo completo di seeding di un set di lingue al modello di linguaggio,

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

Snippet di seguito è un parziale del file languages.csv ,

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

È meglio usare CSV :: Table e usare String.encode(universal_newline: true) . Converte CRLF e CR in LF


La gemma smarter_csv stata creata appositamente per questo caso d'uso: leggere i dati dal file CSV e creare rapidamente voci di database.

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

Puoi usare l'opzione chunk_size per leggere N csv-rows alla volta, e poi usare Resque nel loop interno per generare lavori che creeranno i nuovi record, piuttosto che crearli subito - in questo modo puoi diffondere il carico di generare voci a più lavoratori.

Vedi anche: https://github.com/tilo/smarter_csv


La versione più semplice della risposta di yfeldblum, che è più semplice e funziona bene anche con file di grandi dimensioni:

require 'csv'    

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

Non c'è bisogno di with_indifferent_access o symbolize_keys e non c'è bisogno di leggere prima il file in una stringa.

Non mantiene l'intero file in memoria in una sola volta, ma legge riga per riga e crea un Moulding per riga.



Se si desidera utilizzare SmartCSV

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

Rappresenta i dati delimitati da tabulazioni in ogni riga "\t" con righe separate da nuove righe "\n"


Usa questa gemma: https://rubygems.org/gems/active_record_importer

class Moulding < ActiveRecord::Base
  acts_as_importable
end

Quindi ora puoi usare:

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

Assicurati solo che le intestazioni corrispondano ai nomi delle colonne del tuo tavolo


require 'csv'    

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






import