class CSVImporter::Row

A Row from the CSV file.

Using the header, the model_klass and the identifier it builds the model to be persisted.

Public Instance Methods

build_model() click to toggle source
# File lib/csv_importer/row.rb, line 109
def build_model
  model_klass.new
end
csv_attributes() click to toggle source

A hash with this row's attributes

# File lib/csv_importer/row.rb, line 30
def csv_attributes
  @csv_attributes ||= Hash[header.column_names.zip(row_array)]
end
errors() click to toggle source

Error from the model mapped back to the CSV header if we can

# File lib/csv_importer/row.rb, line 78
def errors
  Hash[
    model.errors.to_hash.map do |attribute, errors|
      if column_name = header.column_name_for_model_attribute(attribute)
        [column_name, errors.last]
      else
        [attribute, errors.last]
      end
    end
  ]
end
find_model() click to toggle source
# File lib/csv_importer/row.rb, line 94
def find_model
  return nil if identifiers.nil?

  model = build_model
  set_attributes(model)

  identifiers = model_identifiers(model)
  return nil if identifiers.empty?

  query = Hash[
    identifiers.map { |identifier| [ identifier, model.public_send(identifier) ] }
  ]
  model_klass.find_by(query)
end
find_or_build_model() click to toggle source
# File lib/csv_importer/row.rb, line 90
def find_or_build_model
  find_model || build_model
end
model() click to toggle source

The model to be persisted

# File lib/csv_importer/row.rb, line 18
def model
  @model ||= begin
    model = find_or_build_model

    set_attributes(model)

    after_build_blocks.each { |block| instance_exec(model, &block) }
    model
  end
end
set_attribute(model, column, csv_value) click to toggle source

Set the attribute using the column_definition and the csv_value

# File lib/csv_importer/row.rb, line 53
def set_attribute(model, column, csv_value)
  column_definition = column.definition
  transformer = column_definition.to
  if transformer.respond_to?(:call)
    arity = transformer.is_a?(Proc) ? transformer.arity : transformer.method(:call).arity

    case arity
    when 1 # to: ->(email) { email.downcase }
      model.public_send("#{column_definition.name}=", transformer.call(csv_value))
    when 2 # to: ->(published, post) { post.published_at = Time.now if published == "true" }
      transformer.call(csv_value, model)
    when 3 # to: ->(field_value, post, column) { post.hash_field[column.name] = field_value }
      transformer.call(csv_value, model, column)
    else
      raise ArgumentError, "arity: #{transformer.arity.inspect} - `to` can only have 1, 2 or 3 arguments"
    end
  else
    attribute = column_definition.attribute
    model.public_send("#{attribute}=", csv_value)
  end

  model
end
set_attributes(model) click to toggle source

Set attributes

# File lib/csv_importer/row.rb, line 35
def set_attributes(model)
  header.columns.each do |column|
    value = csv_attributes[column.name]
    begin
      value = value.dup if value
    rescue TypeError
      # can't dup Symbols, Integer etc...
    end

    next if column.definition.nil?

    set_attribute(model, column, value)
  end

  model
end
skip!() click to toggle source
# File lib/csv_importer/row.rb, line 113
def skip!
  self.skip = true
end

Private Instance Methods

model_identifiers(model) click to toggle source
# File lib/csv_importer/row.rb, line 119
def model_identifiers(model)
  if identifiers.is_a?(Proc)
    [identifiers.call(model)].flatten
  else
    identifiers
  end
end