class RailsSpreadsheetReader::Base

Constants

BASE_ATTRIBUTES

Attributes

collection[RW]
copied_errors[RW]
record_with_error[RW]
row_number[RW]

Public Class Methods

array_to_hash(arr) click to toggle source

Transform an array [a0, a1, a2, …] to a Hash { a0 => 0, a1 => 1, etc } which is the format required by the formatted_hash method.

# File lib/rails_spreadsheet_reader/base.rb, line 215
def self.array_to_hash(arr)
  Hash[[*arr.map { |e| e.to_sym }.map.with_index]]
end
formatted_hash(array) click to toggle source

Returns the Hash representation of a given array using self.format method (which internally uses self.columns). The keys of this Hash are defined in the self.columns method and the values of each key depends on the order of the columns.

For example, given the following self.columns definition

def self.headers
  [:username, :email, :gender]
end

Or

def self.headers
  { :username => 0, :email => 1, :gender => 2 }
end

Row.formatted([username email@test.cl male]) will return { username: ‘username’, email: ‘email@test.cl’, gender: ‘male’ }

Parameters:

array

Array of values which represents an excel column.

Returns:

Hash representation of the given array which maps columns names to the array values.

# File lib/rails_spreadsheet_reader/base.rb, line 115
def self.formatted_hash(array)

  if format.keys.count > 0
    parsed_row = {}
    format.each_pair { |key, col| parsed_row[key] = array[col] }
    return parsed_row
  end

  return nil
end
headers() click to toggle source

Defines the columns of the excel that the class will read. This method must return a Array of strings/symbols (representing columns names) or a Hash (which map column names to columns indexes).

Array Example

def self.headers
  [:username, :email, :gender]
end

Hash Example

def self.headers
  { :username => 0, :email => 1, :gender => 2 }
end

Returns:

An Array or a Hash defining the columns of the excel.

# File lib/rails_spreadsheet_reader/base.rb, line 85
def self.headers
  fail(
      MethodNotImplementedError,
      'Please implement this method in your class.'
  )
end
last_record() click to toggle source
# File lib/rails_spreadsheet_reader/base.rb, line 32
def self.last_record
  @last_record ||= nil
end
last_record=(record) click to toggle source
# File lib/rails_spreadsheet_reader/base.rb, line 36
def self.last_record=(record)
  @last_record = record
end
models() click to toggle source
# File lib/rails_spreadsheet_reader/base.rb, line 40
def self.models
  fail(
      MethodNotImplementedError,
      'Please implement this method in your class.'
  )
end
new(arr_or_hash = {}) click to toggle source

Generalizes the constructor of ActiveModel::Model to make it work with an array argument. When an array argument is passed, it calls formatted_hash method to generate a Hash and then pass it to the ActiveModel::Model constructor

Parameters:

arr_or_hash

Array or Hash of values which represents an excel column.

Calls superclass method
# File lib/rails_spreadsheet_reader/base.rb, line 135
def initialize(arr_or_hash = {})
  self.copied_errors = ActiveModel::Errors.new(self)
  if arr_or_hash.is_a?(Array)
    super(self.class.formatted_hash(arr_or_hash))
  else
    super(arr_or_hash)
  end
end
open(spreadsheet_file) click to toggle source
# File lib/rails_spreadsheet_reader/base.rb, line 173
def self.open(spreadsheet_file)
  if spreadsheet_file.respond_to?(:original_filename)
    Roo::Spreadsheet.open(spreadsheet_file.path, extension: File.extname(spreadsheet_file.original_filename).delete('.'))
  else
    Roo::Spreadsheet.open(spreadsheet_file)
  end
end
persist(collection) click to toggle source

Persist all rows of collection if they all are valid

Parameters:

row_collection

SpreadsheetReader::RowCollection instance

# File lib/rails_spreadsheet_reader/base.rb, line 149
def self.persist(collection)
  if collection.valid?
    ActiveRecord::Base.transaction do
      collection.each do |row|
        # If any of validations fail ActiveRecord::RecordInvalid gets raised.
        # If any of the before_* callbacks return false the action is cancelled and save! raises ActiveRecord::RecordNotSaved.
        begin
          row.persist!
        rescue ActiveRecord::RecordInvalid => e
          row.record_with_error = e.record
          collection.invalid_row = row
          row.check_record_with_error
          rollback
        rescue ActiveRecord::RecordNotSaved => e
          row.model_with_error = e.record
          collection.invalid_row = row
          row.check_record_with_error
          rollback
        end
      end
    end
  end
end
read(spreadsheet_file) click to toggle source

Read and validates the given spreadsheet_file. Persistence is triggered after all validation pass

Parameters:

spreadsheet_file

File instance

Returns:

row_collection

SpreadsheetReader::RowCollection instance

# File lib/rails_spreadsheet_reader/base.rb, line 190
def self.read(spreadsheet_file)

  if headers.empty?
    raise MethodNotImplementedError
  end

  spreadsheet = open(spreadsheet_file)
  collection = RailsSpreadsheetReader::RowCollection.new

  # Populate collection
  (starting_row..spreadsheet.last_row).each do |row_number|
    parameters = formatted_hash(spreadsheet.row(row_number))
    parameters[:row_number] = row_number
    parameters[:collection] = collection
    collection << self.new(parameters)
  end

  # Validation and persist
  persist(collection)

  collection
end
starting_row() click to toggle source

Defines the starting row of the excel where the class should start reading the data.

Returns:

A integer representing the starting row of the data.

# File lib/rails_spreadsheet_reader/base.rb, line 65
def self.starting_row
  2
end

Private Class Methods

format() click to toggle source

Returns the Hash representation of the defined columns

# File lib/rails_spreadsheet_reader/base.rb, line 222
def self.format

  if headers.is_a?(Array) or headers.is_a?(Hash)
    return headers.is_a?(Array) ? array_to_hash(headers) : headers
  end

  fail(
      InvalidTypeError,
      'Please check that the self.columns implementation returns a instance of Hash or Array.'
  )

end
rollback() click to toggle source

Helper for rollbacks inside after_multiple_row_validations

# File lib/rails_spreadsheet_reader/base.rb, line 236
def self.rollback
  raise ActiveRecord::Rollback
end

Public Instance Methods

check_record_with_error() click to toggle source
# File lib/rails_spreadsheet_reader/base.rb, line 24
def check_record_with_error
  if record_with_error.present? and record_with_error.errors.any?
    record_with_error.errors.full_messages.each do |msg|
      @errors.add(:base, msg)
    end
  end
end
persist!() click to toggle source
# File lib/rails_spreadsheet_reader/base.rb, line 47
def persist!
  models = self.class.models.is_a?(Array) ? self.class.models : [self.class.models]
  models.each do |model|
    method_name = model.model_name.human.downcase
    if respond_to?(method_name)
      instance = model.new(send(model.model_name.human.downcase))
    else
      instance = model.new(as_json(except: BASE_ATTRIBUTES))
    end
    instance.save!
  end
end