我正在尝试将数据从CSV上传到我的Modular Rails应用程序中,所以我创建了一个rake文件来轻松实现。以下是代码:
import.rake
require 'csv'
namespace :import do
desc 'Import users from csv'
task users: :environment do
# filename = File.join Rails.root, '/engines/csv_importer/people.csv'
filename = File.join Rails.root, 'engines', 'csv_importer', 'people.csv'
counter = 0
duplicate_counter = 0
user = []
CSV.foreach(filename, headers: true, header_converters: :symbol) do |row|
user = CsvImporter::User.create row.to_h
if user.persisted?
counter += 1
else
duplicate_counter += 1
end
end
p "Duplicate record: #{user.email_address} - #{user.errors.full_messages.join(',')}" if user.errors.any?
p "Imported #{counter} users, #{duplicate_counter} duplicate rows ain't added"
end
end
user.rb
module CsvImporter
class User < ApplicationRecord
validates :email_address, uniqueness: true
end
end
数据库
现在的问题是,没有名称和电子邮件地址的行也会导入到我的数据库中,这是我不想要的。我在模型上使用了回调 - before_save
,但我认为它不是一个强大的解决方案,可以过滤掉没有名称和电子邮件地址的行保存到我的数据库中。
感谢。
答案 0 :(得分:1)
您可以在模型中添加状态验证,其语法与唯一性验证非常相似:
module CsvImporter
class User < ApplicationRecord
validates :name, :email_address, presence: true
validates :email_address, uniqueness: true
end
end
在导入脚本中,您还可以声明性地跳过任何不符合验证条件的行:
CSV.foreach(filename, headers: true, header_converters: :symbol) do |row|
# Jump to the next row in the CSV because this one is no good.
next unless row[:name].present? && row[:email_address].present?
user = CsvImporter::User.create row.to_h
# . . .
end
我还应该提一下,如果:name
和:email_address
始终存在并且永远不为空(这可能是真的)很重要,您可以/应该添加数据库约束以确保您真的如果没有这些字段,就永远无法创建User
。有一些与ActiveRecord对象that skip the validations交互的方法,所以如果你在不知情的情况下使用其中一个并创建不良记录,你会发现自己很惊讶。
迁移看起来像这样:
class AddNotNullConstraintsToUsers < ActiveRecord::Migration
def change
change_column_null :users, :name, false
change_column_null :users, :email_address, false
end
end
答案 1 :(得分:0)
要实现这些验证,请更改用户定义:
duplicate_counter
在这种情况下,应重命名unimported_counter
,例如{{1}}。