Class: Interchange::Reader

Inherits:
Object
  • Object
show all
Includes:
ActionView::Helpers::TextHelper, Mixins::Logging
Defined in:
lib/interchange/reader.rb

Overview

Handles reading files from the local file system meant for import. Ultimately, we’ll pass a JSON object to the model whose data we’ve loaded, and that model will be responsible for creating a new instance of itself and all of its constituent, wholly owned, related objects.

You use mark_import_operation() with a block in which you call import() one or more times, to perform your import operation.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#operation_resultsObject

Returns the value of attribute operation_results.



16
17
18
# File 'lib/interchange/reader.rb', line 16

def operation_results
  @operation_results
end

Instance Method Details

#import(model_class, cleanup = false, duplicate_strategy = Enums::DuplicateStrategy::SKIP, base_path = 'public/interchange/import/') ⇒ Object

We kick off the import process for all records in the import folder that belong to the provided model class. If not provided, we default to no clean up of files and the skipping of any duplicates.

Parameters:

  • model_class

    The actual top-level model class whose json files we’ll look for and import.

  • cleanup (defaults to: false)

    Defaults to false. If true, this instructs the successful import operations to be followed up with a deletion of the source file for import.

  • duplicate_strategy (defaults to: Enums::DuplicateStrategy::SKIP)

    Defaults to skipping duplicates. Provide a value in module Enums::DuplicateStrategy.

Returns:

  • A hash that summarizes the operation. Included within is another hash that can be used for the Flash that provides an alert or notice summary, as appropriate.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/interchange/reader.rb', line 45

def import(model_class, cleanup=false, duplicate_strategy=Enums::DuplicateStrategy::SKIP, base_path='public/interchange/import/')
  log "Importing files for model class: #{model_class}, with options" \
    "cleanup: #{cleanup}, duplicate_strategy: #{duplicate_strategy}, base_path: #{base_path}"

  @model_class = model_class
  @cleanup_requested = cleanup

  log "Started import for model: #{@model_class.to_s}"

  # Determine directory we will read files from:
  directory = "#{base_path}#{@model_class.to_s.pluralize}"

  # Ensure the directory exists:
  models_path = File.join(Rails.root, directory)
  log "Models path to read from: #{models_path}"

  # Does the directory exist that files of the given model class would be found at?
  if File.exists?(models_path)
    log "Import path '#{models_path}' exists."
    Dir.chdir models_path
    filenames = Dir.glob("*.{js,json}") # The candidate files to import will all have a .json or .js extension.
    log "Matched the following file paths: #{filenames}"

    # Iterate through all the files in the model directory, and attempt to import each one:
    filenames.each do | filename |
      log "#{self.class.name} import(): Processing file '#{filename}'"
      contents = File.read(filename)
      massaged_contents = transform_javascript_format(contents)
      model = @model_class.send :import, massaged_contents, duplicate_strategy

      if model.skip_import?
        log "#{self.class.name} import(): Skipping import of file '#{filename}'"
        process_skipped_import(model, filename)
      elsif model.import_errors.empty?
        log "#{self.class.name} import(): Success at import of file '#{filename}'"
        process_model_save(model, filename)
      else
        log "#{self.class.name} import(): Import failed for file '#{filename}'"
        process_failed_import(model)
      end
    end
  else
    log "No import folder exists at path: #{models_path}"
  end

end

#mark_import_operationObject

Prepares for an import operation and cleans up after it, summarizing the results. Callers must provide a block that makes one or more calls to our import() method to import various models.



21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/interchange/reader.rb', line 21

def mark_import_operation
  # Clear the class cached last-import summary:
  self.class.instance_variable_set(:@last_import_summary, nil)

  # Create a hash we'll return as the result of the import
  @operation_results = { successful: [], failures: [], skipped: [] }

  yield # Hand over control to the block that calls our import() method one or more times

  # Now mark the operation as complete:
  summarize_operation
  self.class.instance_variable_set(:@last_import_summary, @operation_results)
end

#transform_javascript_format(contents) ⇒ Object

This takes a file with camel case keys and makes them underscore keys, recognizable to our Ruby models. Additionally, JavaScript commands that encase the core payload, are stripped out, so that we have valid JSON we can parse.

Doing this whole exercise lets us export to JavaScript files useful for UIAutomation, while having a single format we can also import for ourselves (Mockingjay).



99
100
101
102
103
104
105
106
107
108
109
# File 'lib/interchange/reader.rb', line 99

def transform_javascript_format(contents)
  # Find positions for the start and end braces:
  start_position = contents.index('{')
  end_position = contents.rindex('}')

  # Retrieve the string contents of the file between these braces, inclusive:
  massaged_contents = contents[start_position..end_position]

  # Parse the contents into JSON, and the make all the keys underscore style:
  JSON.parse(massaged_contents).underscore_keys
end