Class: RailsSpreadsheetReader::Base
- Inherits:
-
Object
- Object
- RailsSpreadsheetReader::Base
- Includes:
- ActiveModel::Model, ActiveModel::Validations::Callbacks
- Defined in:
- lib/rails_spreadsheet_reader/base.rb
Defined Under Namespace
Classes: InvalidTypeError, MethodNotImplementedError
Constant Summary collapse
- BASE_ATTRIBUTES =
%w(row_number record_with_error copied_errors collection)
Instance Attribute Summary collapse
-
#collection ⇒ Object
Returns the value of attribute collection.
-
#copied_errors ⇒ Object
Returns the value of attribute copied_errors.
-
#record_with_error ⇒ Object
Returns the value of attribute record_with_error.
-
#row_number ⇒ Object
Returns the value of attribute row_number.
Class Method Summary collapse
-
.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.
-
.formatted_hash(array) ⇒ Object
Returns the Hash representation of a given array using self.format method (which internally uses self.columns).
-
.headers ⇒ Object
Defines the columns of the excel that the class will read.
- .last_record ⇒ Object
- .last_record=(record) ⇒ Object
- .open(spreadsheet_file) ⇒ Object
-
.persist(collection) ⇒ Object
Persist all rows of collection if they all are valid.
-
.read(spreadsheet_file) ⇒ Object
Read and validates the given #spreadsheet_file.
-
.starting_row ⇒ Object
Defines the starting row of the excel where the class should start reading the data.
Instance Method Summary collapse
- #check_record_with_error ⇒ Object
-
#initialize(arr_or_hash = {}) ⇒ Base
constructor
Generalizes the constructor of ActiveModel::Model to make it work with an array argument.
- #models ⇒ Object
- #persist ⇒ Object
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.
135 136 137 138 139 140 141 142 |
# 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 |
Instance Attribute Details
#collection ⇒ Object
Returns the value of attribute collection.
18 19 20 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 18 def collection @collection end |
#copied_errors ⇒ Object
Returns the value of attribute copied_errors.
17 18 19 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 17 def copied_errors @copied_errors end |
#record_with_error ⇒ Object
Returns the value of attribute record_with_error.
16 17 18 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 16 def record_with_error @record_with_error end |
#row_number ⇒ Object
Returns the value of attribute row_number.
15 16 17 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 15 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.
209 210 211 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 209 def self.array_to_hash(arr) Hash[[*arr.map { |e| e.to_sym }.map.with_index]] 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.headers
[:username, :email, :gender]
end
Or
def self.headers
{ :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.
115 116 117 118 119 120 121 122 123 124 |
# 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 ⇒ Object
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.
85 86 87 88 89 90 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 85 def self.headers fail( MethodNotImplementedError, 'Please implement this method in your class.' ) end |
.last_record ⇒ Object
32 33 34 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 32 def self.last_record @last_record ||= nil end |
.last_record=(record) ⇒ Object
36 37 38 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 36 def self.last_record=(record) @last_record = record end |
.open(spreadsheet_file) ⇒ Object
171 172 173 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 171 def self.open(spreadsheet_file) Roo::Spreadsheet.open(spreadsheet_file) end |
.persist(collection) ⇒ Object
Persist all rows of collection if they all are valid
Parameters:
- row_collection
-
SpreadsheetReader::RowCollection instance
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# 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 rollback rescue ActiveRecord::RecordNotSaved => e row.model_with_error = e.record collection.invalid_row = row rollback end end end end end |
.read(spreadsheet_file) ⇒ Object
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
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 184 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 ⇒ Object
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.
65 66 67 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 65 def self.starting_row 2 end |
Instance Method Details
#check_record_with_error ⇒ Object
24 25 26 27 28 29 30 |
# 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..each do |msg| @errors.add(:base, msg) end end end |
#models ⇒ Object
40 41 42 43 44 45 |
# File 'lib/rails_spreadsheet_reader/base.rb', line 40 def models fail( MethodNotImplementedError, 'Please implement this method in your class.' ) end |
#persist ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 |
# 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 |