没有名称或电子邮件地址的行将从CSV导入

时间:2018-05-03 13:52:39

标签: ruby-on-rails ruby

我正在尝试将数据从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

数据库

database image

现在的问题是,没有名称和电子邮件地址的行也会导入到我的数据库中,这是我不想要的。我在模型上使用了回调 - before_save,但我认为它不是一个强大的解决方案,可以过滤掉没有名称和电子邮件地址的行保存到我的数据库中。

感谢。

2 个答案:

答案 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}}。