Class: RailsSpreadsheetReader::Base

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Model
Defined in:
lib/rails_spreadsheet_reader/base.rb

Defined Under Namespace

Classes: InvalidTypeError, MethodNotImplementedError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(arr_or_hash = {}) ⇒ Base

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.



113
114
115
116
117
118
119
# File 'lib/rails_spreadsheet_reader/base.rb', line 113

def initialize(arr_or_hash = {})
  if arr_or_hash.is_a?(Array)
    super(self.class.formatted_hash(arr_or_hash))
  else
    super(arr_or_hash)
  end
end

Instance Attribute Details

#models_with_errorsObject

Returns the value of attribute models_with_errors.



16
17
18
# File 'lib/rails_spreadsheet_reader/base.rb', line 16

def models_with_errors
  @models_with_errors
end

#row_numberObject

Returns the value of attribute row_number.



14
15
16
# File 'lib/rails_spreadsheet_reader/base.rb', line 14

def row_number
  @row_number
end

Class Method Details

.array_to_hash(arr) ⇒ Object

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



206
207
208
# File 'lib/rails_spreadsheet_reader/base.rb', line 206

def self.array_to_hash(arr)
  Hash[[*arr.map { |e| e.to_sym }.map.with_index]]
end

.columnsObject

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.columns
  [:username, :email, :gender]
end

Hash Example

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

Returns:

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



63
64
65
66
67
68
# File 'lib/rails_spreadsheet_reader/base.rb', line 63

def self.columns
  fail(
      MethodNotImplementedError,
      'Please implement this method in your class.'
  )
end

.formatted_hash(array) ⇒ Object

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.columns
  [:username, :email, :gender]
end

Or

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

Row.formatted([username [email protected] male]) will return { username: ‘username’, email: ‘[email protected]’, 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.



93
94
95
96
97
98
99
100
101
102
# File 'lib/rails_spreadsheet_reader/base.rb', line 93

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

.open_spreadsheet(spreadsheet_file) ⇒ Object



174
175
176
# File 'lib/rails_spreadsheet_reader/base.rb', line 174

def self.open_spreadsheet(spreadsheet_file)
  Roo::Spreadsheet.open(spreadsheet_file)
end

.persist(row_collection) ⇒ Object

This method is called after the self.validate_multiple_rows method only if it have not raised an exception. The idea of this method is to persist the row’s data. If there was an error with a certain row, you have to Rollback the valid transactions, set the invalid error to the row_collection and set the row errors to the row object.

Example: def self.persist(row_collection)

User.transaction do
  row_collection.each do |row|
    user = User.new(attr1: row.attr1, attr2: row.attr2, ...)
    unless user.save
      row_collection.set_invalid_row(row, user)  # pass the model with errors as second parameter
      rollback # use the rollback helper to rollback the transaction.
    end
  end
end

end

Parameters:

row_collection

SpreadsheetReader::RowCollection instance



170
171
172
# File 'lib/rails_spreadsheet_reader/base.rb', line 170

def self.persist(row_collection)

end

.read_spreadsheet(spreadsheet_file) ⇒ Object

Read and validates the given #spreadsheet_file. First calls #validate_rows method which run #ActiveModel::Model.valid? on each row. Then calls #validate_multiple_rows and finally ends with #persist

Parameters:

spreadsheet_file

File instance

Returns:

row_collection

SpreadsheetReader::RowCollection instance



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/rails_spreadsheet_reader/base.rb', line 188

def self.read_spreadsheet(spreadsheet_file)

  if columns.empty?
    raise MethodNotImplementedError
  end

  spreadsheet = open_spreadsheet(spreadsheet_file)
  row_collection = RailsSpreadsheetReader::RowCollection.new

  validate_rows(spreadsheet, row_collection)
  validate_multiple_rows(row_collection) if row_collection.valid?
  persist(row_collection) if row_collection.valid?
  row_collection

end

.starting_rowObject

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.



43
44
45
# File 'lib/rails_spreadsheet_reader/base.rb', line 43

def self.starting_row
  2
end

.validate_multiple_rows(row_collection) ⇒ Object

This method is called when all rows of row_collection are valid. The main idea of this method is to run validations that have to do with the set of rows of the excel. For example, you can check here if a excel column is unique:

Example:

def self.validate_multiple_rows(row_collection)

username_list = []
row_collection.each do |row|
  if username_list.include?(row.username)
    row_collection.invalid_row = row
    row.errors[:username] = 'is unique'
  else
    username_list << row.username
  end
end

end

Parameters:

row_collection

SpreadsheetReader::RowCollection instance



143
144
145
# File 'lib/rails_spreadsheet_reader/base.rb', line 143

def self.validate_multiple_rows(row_collection)

end

Instance Method Details

#copy_errors(model) ⇒ Object

Models are added models_with_errors. They will be copied in to self.errors on copy_errors_on_validation callback



33
34
35
36
# File 'lib/rails_spreadsheet_reader/base.rb', line 33

def copy_errors(model)
  self.models_with_errors ||= []
  self.models_with_errors << model
end

#copy_errors_on_validationObject



22
23
24
25
26
27
28
29
# File 'lib/rails_spreadsheet_reader/base.rb', line 22

def copy_errors_on_validation
  self.models_with_errors ||= []
  self.models_with_errors.each do |model|
    model.errors.full_messages.each do |msg|
      errors.add(:base, msg)
    end
  end
end