Ruby on rails CSV工作进程正在锁定数据库
有点新手,我完全搞不懂 我有一个工作人员导入CSV联系人以保存到联系人表(保存之前,它会根据电话或电子邮件检查该联系人是否已存在(在这种情况下,联系人不会保存,但会附加详细信息) 虽然下面的代码在逻辑上正常工作(CSV文件将正确处理),但当此作业运行时,整个数据库将被锁定(因此,当此作业运行时,应用程序的任何用户都无法更新(例如,通过应用程序前端保存新联系人) 所以我的问题是:为什么/什么锁定了整个联系人、电话和电子邮件数据库?我是否违反了ruby on rails的一些原则?我需要做什么来解决这个问题 要点:Ruby on rails CSV工作进程正在锁定数据库,ruby-on-rails,ruby,csv,ruby-on-rails-4,rails-postgresql,Ruby On Rails,Ruby,Csv,Ruby On Rails 4,Rails Postgresql,有点新手,我完全搞不懂 我有一个工作人员导入CSV联系人以保存到联系人表(保存之前,它会根据电话或电子邮件检查该联系人是否已存在(在这种情况下,联系人不会保存,但会附加详细信息) 虽然下面的代码在逻辑上正常工作(CSV文件将正确处理),但当此作业运行时,整个数据库将被锁定(因此,当此作业运行时,应用程序的任何用户都无法更新(例如,通过应用程序前端保存新联系人) 所以我的问题是:为什么/什么锁定了整个联系人、电话和电子邮件数据库?我是否违反了ruby on rails的一些原则?我需要做什么来解决
- 当我们编写此代码时(电子邮件和电话是联系人的一部分) 然后我们将他们创建为儿童模型(因为我们每个联系人有多个电子邮件和电话号码)。---有可能是阵列吗 在数组内导致它锁定
- 当我们第一次编写代码时,它会在每个智能行被删除后保存 检查(我们可以看到它在增加)。现在它似乎是 处理完整CSV文件后保存所有联系人
- 还有别的吗
class ImportCsvFileWorker
def self.perform(csv_file_id)
csv_file = CsvFile.find(csv_file_id)
csv_file.import!
csv_file.send_report! end
end
类别CsvParsingService
attr_accessor :csv_file, :contact
def initialize(csv_file)
@csv_file = csv_file
@contact = nil
end
def perform
Rails.logger.info "[CSV.parsing] Processing new csv file..."
process_csv
csv_file.finish_import!
end
def process_csv
parser = ::ImportData::SmartCsvParser.new(csv_file.file_url)
parser.each do |smart_row|
csv_file.increment!(:total_parsed_records)
begin
self.contact = process_row(smart_row)
rescue => e
row_parse_error(smart_row, e)
end
end
rescue => e # parser error or unexpected error
csv_file.save_import_error(e)
end
private
def process_row(smart_row)
new_contact, existing_records = smart_row.to_contact
self.contact = ContactMergingService.new(csv_file.user, new_contact, existing_records).perform
init_contact_info self.contact
if contact_valid?
save_imported_contact(new_contact)
else
reject_imported_contact(new_contact, smart_row)
end
end
def contact_valid?
self.contact.first_name || self.contact.last_name ||
self.contact.email_addresses.first || self.contact.phone_numbers.first
end
def save_imported_contact(new_contact)
self.contact.save!
csv_file.increment!(:total_imported_records)
log_processed_contacts new_contact
end
def reject_imported_contact(new_contact, smart_row)
Rails.logger.info "[CSV.parsing] Contact rejected. Missing name, email or phone number."
csv_file.increment!(:total_failed_records)
csv_file.invalid_records.create!(
original_row: smart_row.row.to_csv,
contact_errors: ["Contact rejected. Missing name, email or phone number"]
)
log_processed_contacts new_contact
false
end
def row_parse_error(smart_row, e)
csv_file.increment!(:total_failed_records)
csv_file.invalid_records.create!(
original_row: smart_row.row.to_csv,
contact_errors: contact.try(:errors).try(:full_messages)
)
end
def init_contact_info(contact)
unless contact.persisted?
contact.user = csv_file.user
contact.created_by_user = csv_file.user
contact.import_source = csv_file
end
contact.required_salutations_to_set = true # will be used for envelope/letter saluation
end
def log_processed_contacts(new_contact)
Rails.logger.info(
"[CSV.parsing] Records parsed:: parsed: #{csv_file.total_parsed_records}"\
" : imported: #{csv_file.total_imported_records} : failed: "\
"#{csv_file.total_failed_records}"
)
Rails.logger.info(
"[CSV.parsing] Contact- New : #{new_contact.email_addresses.map(&:email)}"\
" : #{new_contact.first_name} : #{new_contact.last_name} "\
"#{new_contact.phone_numbers.map(&:number)} :: Old : "\
"#{self.contact.email_addresses.map(&:email)} :"\
"#{self.contact.phone_numbers.map(&:number)}\n"
)
end
end
下面是合并服务
class ContactMergingService
attr_reader :new_contact, :user
def initialize(user, new_contact, _existing_records)
@user = user
@new_contact = new_contact
@found_records = matching_emails_and_phone_numbers end
def perform
Rails.logger.info "[CSV.merging] Checking if new contact matches existing contact..."
if (existing_contact = existing_contact())
Rails.logger.info "[CSV.merging] Contact match found."
merge(existing_contact, new_contact)
existing_contact
else
Rails.logger.info "[CSV.merging] No contact match found."
binding.pry
new_contact
end end
private
def existing_contact
Rails.logger.info "[CSV.merging] Found records: #{@found_records.inspect}"
if @found_records.present?
@user.contacts.find @found_records.first.owner_id # Fetch first owner
end end
def merge(existing_contact, new_contact)
Rails.logger.info "[CSV.merging] Merging with existing contact (ID: #{existing_contact.id})..."
merge_records(existing_contact, new_contact) end
def merge_records(existing_relation, new_relation)
existing_relation.attributes do |field, value|
if value.blank? && new_relation[field].present?
existing_relation[field] = new_relation[field]
end
end
new_relation.email_addresses.each do |email_address|
Rails.logger.info "[CSV.merging.emails] Email: #{email_address.inspect}"
if existing_relation.email_addresses.find_by(email: email_address.email)
Rails.logger.info "[CSV.merging.emails] Email address exists."
else
Rails.logger.info "[CSV.merging.emails] Email does not already exist. Saving..."
email_address.owner = existing_relation
email_address.save!
end
end
new_relation.phone_numbers.each do |phone_number|
Rails.logger.info "[CSV.merging.phone] Phone Number: #{phone_number.inspect}"
if existing_relation.phone_numbers.find_by(number: phone_number.number)
Rails.logger.info "[CSV.merging.phone] Phone number exists."
else
Rails.logger.info "[CSV.merging.phone] Phone Number does not already exist. Saving..."
phone_number.owner = existing_relation
phone_number.save!
end
end end
def matching_emails_and_phone_numbers
records = []
if @user
records << matching_emails
records << matching_phone_numbers
Rails.logger.info "[CSV.merging] merged records: #{records.inspect}"
records.flatten!
Rails.logger.info "[CSV.merging] flattened records: #{records.inspect}"
records.compact!
Rails.logger.info "[CSV.merging] compacted records: #{records.inspect}"
end
records end
def matching_emails
existing_emails = []
new_contact_emails = @new_contact.email_addresses
Rails.logger.info "[CSV.merging] new_contact_emails: #{new_contact_emails.inspect}"
new_contact_emails.each do |email|
Rails.logger.info "[CSV.merging] Checking for a match on email: #{email.inspect}..."
if existing_email = @user.contact_email_addresses.find_by(email: email.email, primary: email.primary)
Rails.logger.info "[CSV.merging] Found a matching email"
existing_emails << existing_email
else
Rails.logger.info "[CSV.merging] No match found"
false
end
end
existing_emails end
def matching_phone_numbers
existing_phone_numbers = []
@new_contact.phone_numbers.each do |phone_number|
Rails.logger.info "[CSV.merging] Checking for a match on phone_number: #{phone_number.inspect}..."
if existing_phone_number = @user.contact_phone_numbers.find_by(number: phone_number.number)
Rails.logger.info "[CSV.merging] Found a matching phone number"
existing_phone_numbers << existing_phone_number
else
Rails.logger.info "[CSV.merging] No match found"
false
end
end
existing_phone_numbers end
def clean_phone_number(number)
number.gsub(/[\s\-\(\)]+/, "") end
end
class ContactMergingService
属性读取器:新联系人::用户
def初始化(用户、新联系人、现有记录)
@用户=用户
@新触点=新触点
@找到的记录=匹配的电子邮件和电话号码结束
def执行
Rails.logger.info“[CSV.merging]检查新联系人是否与现有联系人匹配…”
如果(现有触点=现有触点())
Rails.logger.info“[CSV.merging]找到匹配的联系人。”
合并(现有联系人、新联系人)
现有联络人
其他的
Rails.logger.info“[CSV.merging]未找到匹配的联系人。”
捆绑,撬动
新联络人
结束
私有的
def现有_联系人
Rails.logger.info“[CSV.merging]找到的记录:{@Found\u records.inspect}”
如果@found\u records.present?
@user.contacts.find@found_records.first.owner_id#获取第一个所有者
结束
def合并(现有联系人、新联系人)
Rails.logger.info“[CSV.merging]正在与现有联系人(ID:#{existing_contact.ID})合并”
合并\u记录(现有\u联系人、新\u联系人)结束
def合并_记录(现有_关系、新_关系)
现有_relation.attributes do |字段,值|
如果value.blank?&新建_关系[field]。是否存在?
现有的_关系[字段]=新的_关系[字段]
结束
结束
新关系。电子邮件地址。每个do电子邮件地址|
Rails.logger.info“[CSV.merging.emails]电子邮件:#{Email_address.inspect}”
如果存在关系。电子邮件地址。查找方式(电子邮件:电子邮件地址。电子邮件)
Rails.logger.info“[CSV.merging.emails]电子邮件地址存在。”
其他的
Rails.logger.info“[CSV.merging.emails]电子邮件不存在。正在保存…”
email\u address.owner=现有的\u关系
电子邮件地址。保存!
结束
结束
新关系、电话号码、每个do电话号码|
Rails.logger.info“[CSV.merging.phone]电话号码:#{phone_Number.inspect}”
如果存在关系。电话号码。查找方式(号码:电话号码。号码)
Rails.logger.info“[CSV.merging.phone]电话号码存在。”
其他的
Rails.logger.info“[CSV.merging.phone]电话号码不存在。正在保存…”
phone\u number.owner=现有的\u关系
电话号码。保存!
结束
结束
def匹配电子邮件和电话号码
记录=[]
如果@user
记录“,
“配偶”=>:配偶,
“手机”=>:手机,
“注释”=>:注释,
“帐户”=>“”,
“Internet忙/闲”=>“”,
}
地址映射={
“地址”=>:地址,
“地址1”=>:街道,
“街道”=>:街道,
“城市”=>:城市,
“状态”=>:状态,
“邮政编码”=>:zip,
“Zip”=>:Zip,
“邮政编码”=>:Zip,
“国家”=>:国家,
“家庭地址”=>:地址,
“家乡街”=>:街道,
“Home Street 2”=>:街道,
“Home Street 3”=>:街道,
“家庭地址邮政信箱”=>:街道,
“母国城市”=>:城市,
“母国”=>:国家,
“家庭邮政编码”=>:zip,
“母国”=>:国家,
“营业地址”=>:地址,
“商业街”=>:商业街,
“商业街2”=>:商业街,
“商业街3”=>:商业街,
“营业地址邮政信箱”=>:街道,
“商业城市”=>:城市,
“业务状态”=>:状态,
“商业邮政编码”=>:zip,
“商业国家”=>:国家,
“其他地址”=>:地址,
“其他街道”=>:街道,
“其他街道2”=>:街道,
“其他街道3”=>:街道,
“其他地址邮政信箱”=>:街道,
“其他城市”=>:城市,
“其他状态”=>:状态,
“其他邮政编码”=>:zip,
“其他国家”=>:国家,
}
电子邮件地址字段=[
“电子邮件”,
“电子邮件地址”,
“电子邮件2地址”,
“电子邮件3地址”,
“电子邮件”,
“电子邮件2地址”,
“电子邮件地址3”
]
电话类型映射={
“电话”=>“主页”,
“主电话”=>“主页”,
“家庭电话”=>“家庭电话”,
“家庭电话2”=>“家庭”,
“手机”=>“手机”,
“家庭传真”=>“传真”,
“商务电话”=>“工作”,
“商务电话2”=>“工作”,
“商务传真”=>“传真”,
“其他电话”=>“其他”,
“其他传真”=>“传真”,
“公司主电话”=>“工作”,
}
def初始化(标题,行)
headers=headers.map{| h |最佳匹配_或_self(h)}
超级(标题,行)
结束
def to_触点
现有电子邮件=现有电话号码=无
contact=contact.new.tap do | contact|
启动\u实例(联系,联系\u MAPPIN
require "fuzzy_match"
require "import_data/base_parser"
module ImportData
class SmartCsvParser < BaseParser
def row_class
::ImportData::SmartCsvRow
end
def each_contact
each { |row| yield row.to_contact[0] }
end
end
class SmartCsvRow < BaseRow
CONTACT_MAPPING = {
"Name" => :name,
"First Name" => :first_name,
"Last Name" => :last_name,
"Middle Name" => "",
"Spouse" => :spouse,
"Mobile Phone" => :mobile_phone,
"Notes" => :notes,
"Account" => "",
"Internet Free Busy" => "",
}
ADDRESS_MAPPING = {
"Address" => :address,
"Address1" => :street,
"Street" => :street,
"City" => :city,
"State" => :state,
"Postal Code" => :zip,
"Zip" => :zip,
"Zip Code" => :zip,
"Country" => :country,
"Home Address" => :address,
"Home Street" => :street,
"Home Street 2" => :street,
"Home Street 3" => :street,
"Home Address PO Box" => :street,
"Home City" => :city,
"Home State" => :state,
"Home Postal Code" => :zip,
"Home Country" => :country,
"Business Address" => :address,
"Business Street" => :street,
"Business Street 2" => :street,
"Business Street 3" => :street,
"Business Address PO Box" => :street,
"Business City" => :city,
"Business State" => :state,
"Business Postal Code" => :zip,
"Business Country" => :country,
"Other Address" => :address,
"Other Street" => :street,
"Other Street 2" => :street,
"Other Street 3" => :street,
"Other Address PO Box" => :street,
"Other City" => :city,
"Other State" => :state,
"Other Postal Code" => :zip,
"Other Country" => :country,
}
EMAIL_ADDRESS_FIELDS = [
"Email",
"E-mail Address",
"Email 2 Address",
"Email 3 Address",
"E-mail",
"E-mail 2 Address",
"E-mail 3 Address"
]
PHONE_TYPE_MAPPINGS = {
"Phone" => "Home",
"Primary Phone" => "Home",
"Home Phone" => "Home",
"Home Phone 2" => "Home",
"Mobile Phone" => "Mobile",
"Home Fax" => "Fax",
"Business Phone" => "Work",
"Business Phone 2" => "Work",
"Business Fax" => "Fax",
"Other Phone" => "Other",
"Other Fax" => "Fax",
"Company Main Phone" => "Work",
}
def initialize(headers, row)
headers = headers.map { |h| best_match_or_self(h) }
super(headers, row)
end
def to_contact
existing_emails = existing_phone_numbers = nil
contact = Contact.new.tap do |contact|
initiate_instance(contact, CONTACT_MAPPING)
address = initiate_instance(Address.new, ADDRESS_MAPPING)
contact.addresses << address if address
email_addresses, existing_emails = initialize_emails(EMAIL_ADDRESS_FIELDS)
contact.email_addresses << email_addresses
phone_numbers, existing_phone_numbers = initialize_phone_numbers(PHONE_TYPE_MAPPINGS)
contact.phone_numbers << phone_numbers
contact
end
existing_records = []
existing_records << existing_emails
existing_records << existing_phone_numbers
existing_records.flatten!
existing_records.compact!
[contact, existing_records]
end
private
def fetch_phone_type field
PHONE_TYPE_MAPPINGS[field]
end
FM = FuzzyMatch.new(CONTACT_MAPPING.keys + ADDRESS_MAPPING.keys + EMAIL_ADDRESS_FIELDS + PHONE_TYPE_MAPPINGS.keys)
def best_match_or_self(header)
# Select if Dice's Coefficient
# choose closet by Levenshtein distance
candidate = FM.find(header, find_all_with_score: true).
select { |(_text, dice, _lev)| dice > 0.5 }.
max_by { |(_text, _dice, lev)| lev }
# if cannot find candidate return header
candidate ? candidate[0] : header
end
end
end
<% branch_name = `git symbolic-ref HEAD 2>/dev/null`.chomp.sub('refs/heads/', '') %>
<% repository_name = `git rev-parse --show-toplevel`.split('/').last.strip %>
development:
adapter: postgresql
database: <%= repository_name %>_development
host: localhost
test:
adapter: postgresql
database: <%= repository_name %>_test
host: localhost
production:
adapter: postgresql
database: <%= repository_name %>_production
host: localhost
Delayed::Backend::ActiveRecord::Job Load (1.5ms) UPDATE "delayed_jobs" SET locked_at = '2016-04-07 17:59:37.569861', locked_by = 'host:tests-MBP-3.att.net pid:9659' WHERE id IN (SELECT "delayed_jobs"."id" FROM "delayed_jobs" WHERE ((run_at <= '2016-04-07 17:59:37.568990' AND (locked_at IS NULL OR locked_at < '2016-04-07 16:29:37.569013') OR locked_by = 'host:tests-MBP-3.att.net pid:9659') AND failed_at IS NULL) ORDER BY priority ASC, run_at ASC LIMIT 1 FOR UPDATE) RETURNING * /*application:AGENTBRIGHT*/
2016-04-07T13:59:37-0400: [Worker(host:tests-MBP-3.att.net pid:9659)] Job ImportCsvFileWorker.perform (id=19) RUNNING
CsvFile Load (0.6ms) SELECT "csv_files".* FROM "csv_files" WHERE "csv_files"."id" = $1 LIMIT 1 /*application:AGENTBRIGHT*/ [["id", 1]]
(0.2ms) BEGIN /*application:AGENTBRIGHT*/
SQL (0.4ms) UPDATE "csv_files" SET "state" = $1, "updated_at" = $2 WHERE "csv_files"."id" = $3 /*application:AGENTBRIGHT*/ [["state", "processing"], ["updated_at", "2016-04-07 17:59:37.632648"], ["id", 1]]
[CSV.parsing] Processing new csv file...
SQL (0.4ms) UPDATE "csv_files" SET "total_parsed_records" = $1, "updated_at" = $2 WHERE "csv_files"."id" = $3 /*application:AGENTBRIGHT*/ [["total_parsed_records", 1], ["updated_at", "2016-04-07 17:59:38.571053"], ["id", 1]]
[CSV.base_row] Initializing emails...
[CSV.base_row]
[CSV.base_row] Email addresses: 0
[CSV.base_row] Existing emails : 0
[CSV.base_row] Initializing phone numbers...
[CSV.base_row] Phone numbers: 0
[CSV.base_row] Existing phone numbers : []
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 /*application:AGENTBRIGHT*/ [["id", 1]]
[CSV.merging] new_contact_emails: #<ActiveRecord::Associations::CollectionProxy []>
[CSV.merging] merged records: [[], []]
[CSV.merging] flattened records: []
[CSV.merging] compacted records: []
[CSV.merging] Checking if new contact matches existing contact...
[CSV.merging] Found records: []
[CSV.merging] No contact match found.
SQL (0.7ms) INSERT INTO "contacts" ("data", "first_name", "user_id", "created_by_user_id", "import_source_id", "import_source_type", "name", "envelope_salutation", "letter_salutation", "created_at", "updated_at", "avatar_color") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" /*application:AGENTBRIGHT*/ [["data", "\"notes\"=>\"Family Name: and XXXX ail\r\nAddress 1: Any Street Point Road\r\nCity: Louisville, \r\nState: TN \r\nZip: 06437\r\n# invited: 2\r\nAdults: 2\r\n\""], ["first_name", "Mary Joe"], ["user_id", 1], ["created_by_user_id", 1], ["import_source_id", 1], ["import_source_type", "CsvFile"], ["name", "Mary Joe Smith"], ["envelope_salutation", ""], ["letter_salutation", "Dear Mary Joe,"], ["created_at", "2016-04-07 17:59:38.763119"], ["updated_at", "2016-04-07 17:59:38.763119"], ["avatar_color", 10]]
SQL (1.0ms) UPDATE "users" SET "contacts_count" = COALESCE("contacts_count", 0) + 1 WHERE "users"."id" = $1 /*application:AGENTBRIGHT*/ [["id", 1]]
SQL (0.4ms) UPDATE "csv_files" SET "total_failed_records" = $1, "updated_at" = $2 WHERE "csv_files"."id" = $3 /*application:AGENTBRIGHT*/ [["total_failed_records", 1], ["updated_at", "2016-04-07 17:59:38.775598"], ["id", 1]]
SQL (1.1ms) INSERT INTO "csv_file_invalid_records" ("original_row", "csv_file_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" /*application:AGENTBRIGHT*/ [["original_row", "Mary Joe Smith,,,,,,,,,,,,,\"Family Name: XXXX \r\nAddress 1: Any Street \r\nCity: Louisville, \r\nState: TN \r\nZip: 37777\r\n# invited: 2\r\nAdults: 2\r\n\",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Normal,,My Contacts;Imported 8/13/15 1;Imported 8/13/15,\n"], ["csv_file_id", 1], ["created_at", "2016-04-07 17:59:38.796886"], ["updated_at", "2016-04-07 17:59:38.796886"]]
SQL (0.4ms) UPDATE "csv_files" SET "total_parsed_records" = $1, "updated_at" = $2 WHERE "csv_files"."id" = $3 /*application:AGENTBRIGHT*/ [["total_parsed_records", 2], ["updated_at", "2016-04-07 17:59:39.744526"], ["id", 1]]
[CSV.base_row] Initializing emails...
[CSV.base_row]
[CSV.base_row] Email addresses: 0
[CSV.base_row] Existing emails : 0
[CSV.base_row] Initializing phone numbers...
[CSV.base_row] Phone numbers: 0
[CSV.base_row] Existing phone numbers : []
[CSV.merging] new_contact_emails: #<ActiveRecord::Associations::CollectionProxy []>
[CSV.merging] merged records: [[], []]
[CSV.merging] flattened records: []
[CSV.merging] compacted records: []
[CSV.merging] Checking if new contact matches existing contact...
[CSV.merging] Found records: []
[CSV.merging] No contact match found.
SQL (0.5ms) INSERT INTO "contacts" ("data", "first_name", "user_id", "created_by_user_id", "import_source_id", "import_source_type", "name", "envelope_salutation", "letter_salutation", "created_at", "updated_at", "avatar_color") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING "id" /*application:AGENTBRIGHT*/ [["data", "\"notes\"=>\"Family Name: Xyzlastname\r\nAddress 1: 100 Village Drive #C101\r\nCity: Somecity, \r\nState: MA \r\nZip: 07827\r\n# invited: 1\r\nAdults: 1\r\n\""], ["first_name", "ABC"], ["user_id", 1], ["created_by_user_id", 1], ["import_source_id", 1], ["import_source_type", "CsvFile"], ["name", "ABC"], ["envelope_salutation", ""], ["letter_salutation", "Dear ABC,"], ["created_at", "2016-04-07 17:59:39.753055"], ["updated_at", "2016-04-07 17:59:39.753055"], ["avatar_color", 4]]
SQL (0.7ms) UPDATE "users" SET "contacts_count" = COALESCE("contacts_count", 0) + 1 WHERE "users"."id" = $1 /*application:AGENTBRIGHT*/ [["id", 1]]
SQL (0.4ms) UPDATE "csv_files" SET "total_failed_records" = $1, "updated_at" = $2 WHERE "csv_files"."id" = $3 /*application:AGENTBRIGHT*/ [["total_failed_records", 2], ["updated_at", "2016-04-07 17:59:39.763091"], ["id", 1]]
SQL (0.4ms) INSERT INTO "csv_file_invalid_records" ("original_row", "csv_file_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" /*application:AGENTBRIGHT*/ [["original_row", "Avi,,,,,,,,,,,,,\"Family Name: Xyzlastname\r\nAddress 1: 100 Village Drive #C101\r\nCity: SomeCity, \r\nState: MA \r\nZip: 06777\r\n# invited: 1\r\nAdults: 1\r\n\",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Normal,,My Contacts;Imported 8/13/15 1;Imported 8/13/15,\n"], ["csv_file_id", 1], ["created_at", "2016-04-07 17:59:39.767706"], ["updated_at", "2016-04-07 17:59:39.767706"]]
SQL (0.4ms) UPDATE "csv_files" SET "total_parsed_records" = $1, "updated_at" = $2 WHERE "csv_files"."id" = $3 /*application:AGENTBRIGHT*/ [["total_parsed_records", 3], ["updated_at", "2016-04-07 17:59:40.761966"], ["id", 1]]
[CSV.base_row] Initializing emails...
[CSV.base_row]
[CSV.base_row] Email addresses: 0
[CSV.base_ro
User.create([{email: "joe@example.com", name: "Joe"}, {email: "Ann", name: "Steve"}])