app/models/loop_source.rb
def parse_file status, source_file_obj
    existing_structure = self.loop_item_type.present?

    # keep track of the errors
    status[:errors] = []

    # keep track of the line and column being analised, for error reporting.
    status[:line] = 0
    status[:column] = 0

    # save the headers and the items
    status[:headers] = []
    status[:items] = []

    # auxiliar hash, to avoid repetition
    created_items = {}

    # read the file into a table
    begin
      if File.open(source_file_obj.source.path, &:readline).match(/;/) == nil
        separator = ','
      else
        separator = ';'
      end

      table = CSV.read(source_file_obj.source.path, {
        :quote_char =>'"',
        :col_sep =>separator,
        :row_sep =>:auto,
        :headers => :first_row
      })
    rescue => e
      status[:errors] << e.message
      return false
    end
    #get the headers
    status[:headers] = table.headers
    item_types = {}

    if !self.parse_source_headers(status, item_types, existing_structure)
      return false
    end

    default_language = self.questionnaire
      .questionnaire_fields
      .find_by_is_default_language(true)
      .language

    table.each do |row|
      status[:line] += 1

      # Start with parent as nil (because the first element of each line is the root of the nested set, and looping structure)
      # there is also an hierarchy between items.
      parent = nil

      # and then for each item of the row
      row_as_a = row.to_a

      row_as_a.each_index do |i| # row_as_a[i][0] => item_type ; row_as_a[i][1] => loop_item_names
        created_items[i.to_s] ||= {}

        if row_as_a[i][1].present? # if there's no name, there's no item
          the_val = row_as_a[i][1].squeeze(" ").strip
          the_type = row_as_a[i][0].squeeze(" ").strip
          the_type.slice!(0) if the_type[0] == '#'
          status[:column] += 1

          if existing_structure && (existing_item=(item_types[the_type].existing_item_with(the_val, parent, default_language)))
            parent = existing_item
            next
          end

          # loop_item_names in downcase for comparison purposes. So that the file doesn't need to be case sensitive.
          item_details = {:name => the_val.downcase, :parent => parent.nil? ? "parent_empty" : parent.id}
          item_hash = Digest::MD5.hexdigest(item_details.to_s)

          # check if item was previously added
          if created_items[i.to_s][item_hash]
            #set this item as the parent
            parent = LoopItem.find(created_items[i.to_s][item_hash])
          else # otherwise create a new item
            son = LoopItem.new()#:item_name => row_as_a[i][1].to_s)
            son.loop_item_type_id = item_types[the_type].id
            # set it's parent, if parent is defined, otherwise it will be a root item.
            if parent
              son.parent = parent
            end

            # handle loopItemNames. Find or create it and then add it to the loop_item and loop_item_type and loop_source
            begin
              l_item_name = item_types[the_type].loop_item_name_with(the_val, default_language, self)
            rescue ActiveRecord::RecordInvalid => e
              status[:errors] << "ERROR: line #{status[:line]} and column #{status[:column]}. Check the character encoding of your file."
              next
            end
            son.loop_item_name = l_item_name

            # set sort_index => total loop_items before adding the new item to it, so that it is the index of the total of items[0 to total]
            # son.sort_index = item_types[the_type].loop_items.count #set the sort_index to be one more than the parent's. The default is zero, so the parent starts at zero.
            son.sort_index = item_types[the_type].loop_items.empty? ? 0 : item_types[the_type].loop_items.maximum("sort_index") + 1

            # save the son
            if son.save
              #add the item to the hash of created items
              created_items[i.to_s][item_hash] = son.id
              status[:items] << son

              #redefine the parent for next iteration
              parent = son
            else
              status[:errors] << "Problem in line " + status[:line] + ", and column " + status[:column]
              return false
            end
          end
        end
      end

      status[:column] = 0
    end
  end
# load the loop_items of a loop_source from a file.
load the loop_items of a loop_source from a file.
load the loop_items of a loop_source from a file .
def parse_file status, source_file_obj
    existing_structure = self.loop_item_type.present?
    status[:errors] = []
    status[:line] = 0
    status[:column] = 0
    status[:headers] = []
    status[:items] = []
    created_items = {}
    begin
      if File.open(source_file_obj.source.path, &:readline).match(/;/) == nil
        separator = ','
      else
        separator = ';'
      end
      table = CSV.read(source_file_obj.source.path, {
        :quote_char =>'"',
        :col_sep =>separator,
        :row_sep =>:auto,
        :headers => :first_row
      })
    rescue => e
      status[:errors] << e.message
      return false
    end
    status[:headers] = table.headers
    item_types = {}
    if !self.parse_source_headers(status, item_types, existing_structure)
      return false
    end
    default_language = self.questionnaire
      .questionnaire_fields
      .find_by_is_default_language(true)
      .language
    table.each do |row|
      status[:line] += 1
      parent = nil
      row_as_a = row.to_a
      row_as_a.each_index do |i| 
        created_items[i.to_s] ||= {}
        if row_as_a[i][1].present? 
          the_val = row_as_a[i][1].squeeze(" ").strip
          the_type = row_as_a[i][0].squeeze(" ").strip
          the_type.slice!(0) if the_type[0] == '#'
          status[:column] += 1
          if existing_structure && (existing_item=(item_types[the_type].existing_item_with(the_val, parent, default_language)))
            parent = existing_item
            next
          end
          item_details = {:name => the_val.downcase, :parent => parent.nil? ? "parent_empty" : parent.id}
          item_hash = Digest::MD5.hexdigest(item_details.to_s)
          if created_items[i.to_s][item_hash]
            parent = LoopItem.find(created_items[i.to_s][item_hash])
          else 
            son = LoopItem.new()
            son.loop_item_type_id = item_types[the_type].id
            if parent
              son.parent = parent
            end
            begin
              l_item_name = item_types[the_type].loop_item_name_with(the_val, default_language, self)
            rescue ActiveRecord::RecordInvalid => e
              status[:errors] << "ERROR: line #{status[:line]} and column #{status[:column]}. Check the character encoding of your file."
              next
            end
            son.loop_item_name = l_item_name
            son.sort_index = item_types[the_type].loop_items.empty? ? 0 : item_types[the_type].loop_items.maximum("sort_index") + 1
            if son.save
              created_items[i.to_s][item_hash] = son.id
              status[:items] << son
              parent = son
            else
              status[:errors] << "Problem in line " + status[:line] + ", and column " + status[:column]
              return false
            end
          end
        end
      end
      status[:column] = 0
    end
  end
def parse_file status , source_file_obj existing_structure = self . loop_item_type . present? status [ :errors ] = [ ] status [ :line ] = 0 status [ :column ] = 0 status [ :headers ] = [ ] status [ :items ] = [ ] created_items = { } begin if File . open ( source_file_obj . source . path , & :readline ) . match ( / ; / ) == nil separator = ',' else separator = ';' end table = CSV . read ( source_file_obj . source . path , { :quote_char => '"' , :col_sep => separator , :row_sep => :auto , :headers => :first_row } ) rescue => e status [ :errors ] << e . message return false end status [ :headers ] = table . headers item_types = { } if ! self . parse_source_headers ( status , item_types , existing_structure ) return false end default_language = self . questionnaire . questionnaire_fields . find_by_is_default_language ( true ) . language table . each do | row | status [ :line ] += 1 parent = nil row_as_a = row . to_a row_as_a . each_index do | i | created_items [ i . to_s ] ||= { } if row_as_a [ i ] [ 1 ] . present? the_val = row_as_a [ i ] [ 1 ] . squeeze ( " " ) . strip the_type = row_as_a [ i ] [ 0 ] . squeeze ( " " ) . strip the_type . slice! ( 0 ) if the_type [ 0 ] == '#' status [ :column ] += 1 if existing_structure && ( existing_item = ( item_types [ the_type ] . existing_item_with ( the_val , parent , default_language ) ) ) parent = existing_item next end item_details = { :name => the_val . downcase , :parent => parent . nil? ? "parent_empty" : parent . id } item_hash = Digest :: MD5 . hexdigest ( item_details . to_s ) if created_items [ i . to_s ] [ item_hash ] parent = LoopItem . find ( created_items [ i . to_s ] [ item_hash ] ) else son = LoopItem . new ( ) son . loop_item_type_id = item_types [ the_type ] . id if parent son . parent = parent end begin l_item_name = item_types [ the_type ] . loop_item_name_with ( the_val , default_language , self ) rescue ActiveRecord :: RecordInvalid => e status [ :errors ] << "ERROR: line #{status[:line]} and column #{status[:column]}. Check the character encoding of your file." next end son . loop_item_name = l_item_name son . sort_index = item_types [ the_type ] . loop_items . empty? ? 0 : item_types [ the_type ] . loop_items . maximum ( "sort_index" ) + 1 if son . save created_items [ i . to_s ] [ item_hash ] = son . id status [ :items ] << son parent = son else status [ :errors ] << "Problem in line " + status [ :line ] + ", and column " + status [ :column ] return false end end end end status [ :column ] = 0 end end
load the loop_items of a loop_source from a file.
load the loop_items of a loop_source from a file .
# keep track of the errors # keep track of the line and column being analised, for error reporting. # save the headers and the items # auxiliar hash, to avoid repetition # read the file into a table #get the headers # Start with parent as nil (because the first element of each line is the root of the nested set, and looping structure) # there is also an hierarchy between items. # and then for each item of the row # row_as_a[i][0] => item_type ; row_as_a[i][1] => loop_item_names # if there's no name, there's no item # loop_item_names in downcase for comparison purposes. So that the file doesn't need to be case sensitive. # check if item was previously added #set this item as the parent # otherwise create a new item #:item_name => row_as_a[i][1].to_s) # set it's parent, if parent is defined, otherwise it will be a root item. # handle loopItemNames. Find or create it and then add it to the loop_item and loop_item_type and loop_source # set sort_index => total loop_items before adding the new item to it, so that it is the index of the total of items[0 to total] # son.sort_index = item_types[the_type].loop_items.count #set the sort_index to be one more than the parent's. The default is zero, so the parent starts at zero. # save the son #add the item to the hash of created items #redefine the parent for next iteration
status
source_file_obj