app/models/local_census_records/import.rb
require "csv"
class LocalCensusRecords::Import
include ActiveModel::Model
ATTRIBUTES = %w[document_type document_number date_of_birth postal_code].freeze
ALLOWED_FILE_EXTENSIONS = %w[csv].freeze
attr_accessor :file, :created_records, :invalid_records
validates :file, presence: true
validate :file_extension, if: -> { @file.present? }
validate :file_headers_definition, if: -> { @file.present? && valid_extension? }
def initialize(attributes = {})
if attributes.present?
attributes.each do |attr, value|
public_send("#{attr}=", value)
end
end
@created_records = []
@invalid_records = []
end
def save
return false if invalid?
CSV.open(file.path, headers: true).each do |row|
next if empty_row?(row)
process_row row
end
true
end
def save!
validate! && save
end
private
def process_row(row)
local_census_record = build_local_census_record(row)
if local_census_record.invalid?
invalid_records << local_census_record
else
local_census_record.save!
created_records << local_census_record
end
end
def build_local_census_record(row)
local_census_record = LocalCensusRecord.new
local_census_record.attributes = row.to_hash.slice(*ATTRIBUTES)
local_census_record
end
def empty_row?(row)
row.all? { |_, cell| cell.nil? }
end
def file_extension
return if valid_extension?
errors.add :file, :extension, valid_extensions: ALLOWED_FILE_EXTENSIONS.join(", ")
end
def fetch_file_headers
CSV.open(file.path, &:readline)
end
def file_headers_definition
headers = fetch_file_headers
return if headers.all? { |header| ATTRIBUTES.include? header } &&
ATTRIBUTES.all? { |attr| headers.include? attr }
errors.add :file, :headers, required_headers: ATTRIBUTES.join(", ")
end
def valid_extension?
ALLOWED_FILE_EXTENSIONS.include? extension
end
def extension
File.extname(file.original_filename).delete(".")
end
end