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.



98
99
100
101
102
103
104
# File 'lib/rails_spreadsheet_reader/base.rb', line 98

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

#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.



191
192
193
# File 'lib/rails_spreadsheet_reader/base.rb', line 191

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.



48
49
50
51
52
53
# File 'lib/rails_spreadsheet_reader/base.rb', line 48

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.



78
79
80
81
82
83
84
85
86
87
# File 'lib/rails_spreadsheet_reader/base.rb', line 78

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



159
160
161
# File 'lib/rails_spreadsheet_reader/base.rb', line 159

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



155
156
157
# File 'lib/rails_spreadsheet_reader/base.rb', line 155

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



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/rails_spreadsheet_reader/base.rb', line 173

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.



28
29
30
# File 'lib/rails_spreadsheet_reader/base.rb', line 28

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



128
129
130
# File 'lib/rails_spreadsheet_reader/base.rb', line 128

def self.validate_multiple_rows(row_collection)

end

Instance Method Details

#copy_errors(model) ⇒ Object

Copy a ActiveModel::Model errors



17
18
19
20
21
# File 'lib/rails_spreadsheet_reader/base.rb', line 17

def copy_errors(model)
  model.errors.full_messages.each do |msg|
    errors.add(:base, msg)
  end
end