我想将数据从CSV文件导入到现有的数据库表中。我不想保存CSV文件,只是从它的数据,并把它放入现有的表。我使用Ruby 1.9.2和Rails 3。

这是我的桌子:

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

你能给我一些代码,告诉我最好的方法,谢谢。


当前回答

这是有帮助的。它也有代码示例:

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

或者对rake任务做同样的事情:

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

其他回答

yfeldblum回答的简单版本,更简单,也适用于大文件:

require 'csv'    

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

不需要with_indifferent_access或symbolize_keys,也不需要先将文件读入字符串。

它不把整个文件一次保存在内存中,而是逐行读取,每行创建一个Moulding。

更好的方法是将其包含在rake任务中。创建导入。Rake文件在/lib/tasks/中,并将此代码放到该文件中。

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

然后在您的终端上运行此命令rake csv_model_import[file.csv,Name_of_the_Model]

我知道这是一个老问题,但它仍然在谷歌的前10个链接。

逐个保存行不是很有效,因为它会导致循环中的数据库调用,您最好避免这种情况,特别是当您需要插入大量数据时。

使用批处理插入更好(而且更快)。

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

您可以手动构建这样的查询,而不是使用Model.connection。执行(原始SQL字符串)(不推荐) 或者使用gem activerecord-import(它于2010年8月11日首次发布)在这种情况下,只需将数据放在数组行中并调用Model。进口的行

详情请参阅gem文档

最好将数据库相关的进程包装在事务块中。代码片段blow是将一组语言播种到语言模型的完整过程,

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

下面的代码片段是languages.csv文件的一部分,

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

使用这个宝石: https://rubygems.org/gems/active_record_importer

class Moulding < ActiveRecord::Base
  acts_as_importable
end

那么你现在可以使用:

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

只要确保标题与表的列名匹配即可