class ActiveRecord::Associations::CollectionAssociation

def bulk_import(*args, &block)

def bulk_import(*args, &block)
  unless owner.persisted?
    raise ActiveRecord::RecordNotSaved, "You cannot call import unless the parent is saved"
  end
  options = args.last.is_a?(Hash) ? args.pop : {}
  model_klass = reflection.klass
  symbolized_foreign_key = reflection.foreign_key.to_sym
  symbolized_column_names = if model_klass.connection.respond_to?(:supports_virtual_columns?) && model_klass.connection.supports_virtual_columns?
    model_klass.columns.reject(&:virtual?).map { |c| c.name.to_sym }
  else
    model_klass.column_names.map(&:to_sym)
  end
  owner_primary_key = reflection.active_record_primary_key.to_sym
  owner_primary_key_value = owner.send(owner_primary_key)
  # assume array of model objects
  if args.last.is_a?( Array ) && args.last.first.is_a?(ActiveRecord::Base)
    if args.length == 2
      models = args.last
      column_names = args.first.dup
    else
      models = args.first
      column_names = symbolized_column_names
    end
    unless symbolized_column_names.include?(symbolized_foreign_key)
      column_names << symbolized_foreign_key
    end
    models.each do |m|
      m.public_send "#{symbolized_foreign_key}=", owner_primary_key_value
      m.public_send "#{reflection.type}=", owner.class.name if reflection.type
    end
    return model_klass.bulk_import column_names, models, options
  # supports array of hash objects
  elsif args.last.is_a?( Array ) && args.last.first.is_a?(Hash)
    if args.length == 2
      array_of_hashes = args.last
      column_names = args.first.dup
      allow_extra_hash_keys = true
    else
      array_of_hashes = args.first
      column_names = array_of_hashes.first.keys
      allow_extra_hash_keys = false
    end
    symbolized_column_names = column_names.map(&:to_sym)
    unless symbolized_column_names.include?(symbolized_foreign_key)
      column_names << symbolized_foreign_key
    end
    if reflection.type && !symbolized_column_names.include?(reflection.type.to_sym)
      column_names << reflection.type.to_sym
    end
    array_of_attributes = array_of_hashes.map do |h|
      error_message = model_klass.send(:validate_hash_import, h, symbolized_column_names, allow_extra_hash_keys)
      raise ArgumentError, error_message if error_message
      column_names.map do |key|
        if key == symbolized_foreign_key
          owner_primary_key_value
        elsif reflection.type && key == reflection.type.to_sym
          owner.class.name
        else
          h[key]
        end
      end
    end
    return model_klass.bulk_import column_names, array_of_attributes, options
  # supports empty array
  elsif args.last.is_a?( Array ) && args.last.empty?
    return ActiveRecord::Import::Result.new([], 0, [])
  # supports 2-element array and array
  elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
    column_names, array_of_attributes = args
    # dup the passed args so we don't modify unintentionally
    column_names = column_names.dup
    array_of_attributes = array_of_attributes.map(&:dup)
    symbolized_column_names = column_names.map(&:to_sym)
    if symbolized_column_names.include?(symbolized_foreign_key)
      index = symbolized_column_names.index(symbolized_foreign_key)
      array_of_attributes.each { |attrs| attrs[index] = owner_primary_key_value }
    else
      column_names << symbolized_foreign_key
      array_of_attributes.each { |attrs| attrs << owner_primary_key_value }
    end
    if reflection.type
      symbolized_type = reflection.type.to_sym
      if symbolized_column_names.include?(symbolized_type)
        index = symbolized_column_names.index(symbolized_type)
        array_of_attributes.each { |attrs| attrs[index] = owner.class.name }
      else
        column_names << symbolized_type
        array_of_attributes.each { |attrs| attrs << owner.class.name }
      end
    end
    return model_klass.bulk_import column_names, array_of_attributes, options
  else
    raise ArgumentError, "Invalid arguments!"
  end
end