Module: Basepack::Import::ModelDragonfly

Extended by:
ActiveSupport::Concern
Included in:
Import
Defined in:
lib/basepack/import/model_dragonfly.rb

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#file_typeObject



106
107
108
109
110
111
112
113
114
115
# 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, &block) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# 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) ⇒ Object



174
175
176
177
178
179
180
# 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_csvObject



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# 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) ⇒ Object



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# 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_classObject



153
154
155
# File 'lib/basepack/import/model_dragonfly.rb', line 153

def importable_class
  klass.constantize
end

#open_file(encoding_from = nil, &block) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# 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) ⇒ Object



138
139
140
# 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) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# 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(&block) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# 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_modelObject



142
143
144
145
146
147
148
149
150
151
# 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