Ruby on Rails-Import danych z pliku CSV

Chciałbym zaimportować dane z pliku CSV do istniejącej tabeli bazy danych. Nie chcę zapisywać pliku CSV, po prostu pobieram z niego Dane i umieszczam je w istniejącej tabeli. Używam Ruby 1.9.2 i Rails 3.

To jest mój stół:

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
Możesz dać mi jakiś kod, żeby pokazać mi jak najlepiej to zrobić, dzięki.
Author: freshest, 2010-12-10

11 answers

require 'csv'    

csv_text = File.read('...')
csv = CSV.parse(csv_text, :headers => true)
csv.each do |row|
  Moulding.create!(row.to_hash)
end
 392
Author: yfeldblum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-23 00:18:01

Prostsza wersja odpowiedzi yfeldbluma, która jest prostsza i działa dobrze również z dużymi plikami:

require 'csv'    

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

Nie ma potrzeby stosowania with_indifferent_access Ani symbolize_keys, i nie ma potrzeby najpierw odczytywania w pliku do ciągu znaków.

Nie przechowuje całego pliku w pamięci na raz, ale czyta w linii po linii i tworzy formowanie w linii.

 210
Author: Tom De Leu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-10 20:16:07

Gem smarter_csv został stworzony specjalnie dla tego przypadku użycia: do odczytu danych z pliku CSV i szybkiego tworzenia wpisów w bazie danych.

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

Możesz użyć opcji chunk_size, aby odczytać N wierszy csv naraz, a następnie użyć Resque w wewnętrznej pętli, aby wygenerować zadania, które utworzą nowe rekordy, zamiast tworzyć je od razu - w ten sposób możesz rozłożyć obciążenie generowania wpisów na wiele worków.

[[3]}Zobacz: https://github.com/tilo/smarter_csv
 11
Author: Tilo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-11 10:23:58

Możesz spróbować 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

Jeśli tego chcesz, możesz również rozważyć pozbycie się auto-inkrementacyjnego klucza podstawowego z tabeli i ustawienie klucza podstawowego na name. Alternatywnie, jeśli istnieje pewna kombinacja atrybutów tworzących klucz podstawowy, użyj go jako selektora. Żaden indeks nie jest konieczny, po prostu przyspieszy.

 5
Author: Seamus Abshere,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-07 21:05:53

To może pomóc. Ma też przykłady kodu:

Http://csv-mapper.rubyforge.org/

Lub za zadanie rake za zrobienie tego samego:

Http://erikonrails.snowedin.net/?p=212

 4
Author: Kalyan Maddu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-10 16:14:56

Lepiej jest zawinąć proces związany z bazą danych wewnątrz transaction bloku. Kod snippet blow to pełny proces zaszeregowania zestawu języków do modelu języka,

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

Poniżej fragment pliku languages.csv,

aa,Afar
ab,Abkhazian
af,Afrikaans
ak,Akan
am,Amharic
ar,Arabic
as,Assamese
ay,Aymara
az,Azerbaijani
ba,Bashkir
...
 3
Author: Metropolis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-03 03:27:42

Wiem, że to stare pytanie, ale nadal w pierwszych 10 linkach w google.

Nie jest zbyt wydajne zapisywanie wierszy jeden po drugim, ponieważ powoduje wywołanie bazy danych w pętli i lepiej tego unikać, zwłaszcza gdy trzeba wstawić ogromne porcje danych.

Lepiej (i znacznie szybciej) używać wsadowej wkładki.

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

Możesz zbudować takie zapytanie ręcznie i zrobić Model.connection.execute(RAW SQL STRING) (nie polecane) lub użyj gem activerecord-import (został wydany po raz pierwszy 11 sierpnia 2010) w tym przypadku po prostu umieść dane w tablicy rows i wywołaj Model.import rows

Szczegóły można znaleźć w dokumentach gem

 1
Author: Yaroslav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-31 01:20:10

Użyj tego klejnotu: https://rubygems.org/gems/active_record_importer

class Moulding < ActiveRecord::Base
  acts_as_importable
end

Wtedy możesz teraz użyć:

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

Upewnij się, że nagłówki pasują do nazw kolumn tabeli

 0
Author: Michael Nera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-28 07:53:01

Lepszym sposobem jest włączenie go do zadania rake. Utwórz import.plik rake w / lib / tasks / i umieść ten kod w tym pliku.

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

Następnie uruchom tę komendę w swoim terminalu rake csv_model_import[file.csv,Name_of_the_Model]

 0
Author: Ipsagel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-24 07:26:19

Lepiej jest użyć CSV:: Table i użyć String.encode(universal_newline: true). Konwertuje CRLF i CR na LF

 -2
Author: ysk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-31 07:16:45

Jeśli chcesz użyć SmartCSV

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

Przedstawia dane rozdzielane tabulatorami w każdym wierszu {[1] } z wierszami oddzielonymi nowymi wierszami "\n"

 -3
Author: Maged Makled,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-26 18:59:36