module Basepack::Import::ModelDragonfly

Attributes

current_ability[RW]

Public Instance Methods

file_type() click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 106
def file_type
  case file.try(:mime_type)
  when "text/csv", "text/plain"
    :csv
  when 'text/xml', 'application/xml'
    :xml
  else
    :unknown
  end
end
import_attributes(attrs) { |object| ... } click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 250
def import_attributes(attrs, &block)
  if attrs.present?
    transaction do
      model = importable_class

      begin
        object = model.try(:find_or_initialize_for_import, attrs) ||
                 Basepack::Import::Importable.find_or_initialize_for_import(model, attrs)
      rescue ActiveRecord::RecordNotFound => e # error in finding nested attributes
        #TODO: it is not show particular error in nesed models, shloud be used https://gist.github.com/pehrlich/4710856
        object = model.new
        object.errors[:base] << e.message
      end

      if object.respond_to?(:around_import)
        object.around_import(self) { yield(object) }
      else
        yield(object)
      end
      save!
    end
  end
end
import_data(user_for_ability) click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 174
def import_data(user_for_ability)
  current_ability = Ability.new(user_for_ability)
  start_processing do |import|
    import.current_ability = current_ability
    import.send("import_data_#{import.file_type}")
  end
end
import_data_csv() click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 182
def import_data_csv
  import = self
  ability_attributes = current_ability.attributes_for(:import, importable_class)
  mapping = import.configuration[:mapping] || []
  use_blanks = import.configuration[:blank_vals] == 'use'
  skip_rows = import.num_imported + import.num_errors + 1 # 1==header, if > 1, then import failed and called repeatedly
  idx = 0

  import.open_report do |report|
    if skip_rows == 1
      report << CSV.generate_line(mapping + ["Chyby"], encoding: 'UTF-8')
    end
    import.open_file(import.configuration[:encoding_from] || 'UTF-8') do |f|
      CSV.new(f, col_sep: import.configuration[:col_sep] || ',').each do |row|
        next if row.blank?
        idx += 1
        next if idx <= skip_rows

        attrs = ability_attributes.dup
        row.each_with_index do |data, i|
          attr = mapping[i]
          attrs[attr] = data if attr.present? and (data.present? or use_blanks)
        end

        import_attributes(Rack::Utils.parse_nested_query(attrs.to_query)) do |object|
          unless save_object(object)
            report << CSV.generate_line(row + [object.errors.full_messages.join('; ')], encoding: 'UTF-8')
          end
        end
      end
    end
  end
end
import_data_xml(*a) click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 216
def import_data_xml(*a)
  import = self
  ability_attributes = current_ability.attributes_for(:import, importable_class)
  mapping = import.configuration[:mapping]
  skip_rows = import.num_imported + import.num_errors
  idx = 0

  import.open_report do |report|
    if skip_rows == 0
      report << CSV.generate_line(mapping_hash2row(mapping, mapping) + ["Chyby"], encoding: 'UTF-8')
    end
    import.open_file do |f|
      Nokogiri::XML(f).xpath(configuration[:root]).each do |node|
        next if node.blank?
        idx += 1
        next if idx <= skip_rows

        attrs = ability_attributes.dup
        mapping.each do |attr, xpath|
          next if xpath.blank?
          attr_node = node.search(xpath)
          attrs[attr] = attr_node.first.try(:content) if attr_node.present?
        end

        import_attributes(Rack::Utils.parse_nested_query(attrs.to_query)) do |object|
          unless save_object(object)
            report << CSV.generate_line(mapping_hash2row(attrs, mapping) + [object.errors.full_messages.join('; ')], encoding: 'UTF-8')
          end
        end
      end
    end
  end
end
importable_class() click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 153
def importable_class
  klass.constantize
end
open_file(encoding_from = nil, &block) click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 117
def open_file(encoding_from = nil, &block)
  if encoding_from
    mode = "r:#{encoding_from}:utf-8"
  else
    #guess encoding form first 4M of updated file
    string = File.open(file.path, 'rb:ASCII-8BIT').gets(nil, 40000)
    Basepack::Settings.import.guess_encoding_from.each do |enc|
      string.force_encoding(enc)
      if string.valid_encoding?
        mode = "r:#{enc}:utf-8"
        break
      end
    end

    #defautl encoding if none will be recognized
    mode ||= 'rb:ASCII-8BIT'
  end

  File.open(file.path, mode, &block)
end
open_report(&block) click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 138
def open_report(&block)
  File.open(report.path, "a:utf-8", &block)
end
save_object(object) click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 274
def save_object(object)

  begin
    status = object.errors.empty? ? object.save! : false
  rescue => err #catch the case when custom validation raise an error
    status = false
    object.errors.add(:base, "Raise Internal Error: #{err}") #err.backtrace
  end

  if status
    self.num_imported += 1
    self.importables.build(importable: object)
  else
    self.num_errors += 1
  end
  status
end
start_processing() { |import| ... } click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 157
def start_processing(&block)
  import = self
  unless import.state == "finished"
    unless import.state == "processing"
      name = "report-#{import.id}.csv"
      data = ""
      data.define_singleton_method(:original_filename) { name }
      import.report = data
      import.state = "processing"
      import.save!
      import = self.class.find(import.id) # reload report path
    end
    yield(import)
    import.update_attributes!(state: "finished")
  end
end
validate_klass_is_model() click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 142
def validate_klass_is_model
  begin
    c = klass.constantize
    raise NameError unless c.ancestors.include? ActiveRecord::Base
    false
  rescue NameError
    errors.add(:klass, "is not known model!")
    true
  end
end

Private Instance Methods

mapping_hash2row(attrs, mapping) click to toggle source
# File lib/basepack/import/model_dragonfly.rb, line 294
def mapping_hash2row(attrs, mapping)
  res = mapping.keys.inject({}) { |s, k| s[k] = attrs[k] || ''; s}
  res.to_a.sort { |a,b| a.first <=> b.first }.map(&:last)
end