class ActiveImporter::Base
Constants
- EVENTS
Callbacks
Attributes
header[R]
Implementation
model[R]
Implementation
params[R]
row[R]
Implementation
row_count[R]
row_errors[R]
row_index[R]
Public Class Methods
column(title, field = nil, options = nil, &block)
click to toggle source
# File lib/active_importer/base.rb, line 56 def self.column(title, field = nil, options = nil, &block) title = title.strip if columns[title] raise "Duplicate importer column '#{title}'" end if field.is_a?(Hash) raise "Invalid column '#{title}': expected a single set of options" unless options.nil? options = field field = nil else options ||= {} end if field.nil? && block_given? raise "Invalid column '#{title}': must have a corresponding attribute, or it shouldn't have a block" end columns[title] = { field_name: field, transform: block, optional: !!options[:optional], } end
columns()
click to toggle source
# File lib/active_importer/base.rb, line 24 def self.columns @columns ||= {} end
event_handlers()
click to toggle source
# File lib/active_importer/base.rb, line 130 def self.event_handlers @event_handlers ||= EVENTS.inject({}) { |hash, event| hash.merge({event => []}) } end
fetch_model(&block)
click to toggle source
# File lib/active_importer/base.rb, line 40 def self.fetch_model(&block) @fetch_model_block = block end
import(file, options = {})
click to toggle source
# File lib/active_importer/base.rb, line 81 def self.import(file, options = {}) new(file, options).import end
imports(klass)
click to toggle source
# File lib/active_importer/base.rb, line 20 def self.imports(klass) @model_class = klass end
model_class()
click to toggle source
# File lib/active_importer/base.rb, line 28 def self.model_class @model_class end
new(file, options = {})
click to toggle source
# File lib/active_importer/base.rb, line 168 def initialize(file, options = {}) @row_errors = [] @params = options.delete(:params) @transactional = options.fetch(:transactional, self.class.transactional?) raise "Importer is declared transactional at the class level" if !@transactional && self.class.transactional? @book = Roo::Spreadsheet.open(file, options) load_sheet load_header @data_row_indices = ((@header_index+1)..@book.last_row) @row_count = @data_row_indices.count rescue => e @book = @header = nil @row_count = 0 @row_index = 1 fire_event :import_failed, e raise end
on(event, &block)
click to toggle source
# File lib/active_importer/base.rb, line 134 def self.on(event, &block) raise "Unknown ActiveImporter event '#{event}'" unless EVENTS.include?(event) event_handlers[event] << block end
sheet(index)
click to toggle source
# File lib/active_importer/base.rb, line 36 def self.sheet(index) @sheet_index = index end
skip_rows_block()
click to toggle source
# File lib/active_importer/base.rb, line 52 def self.skip_rows_block @skip_rows_block end
skip_rows_if(&block)
click to toggle source
# File lib/active_importer/base.rb, line 48 def self.skip_rows_if(&block) @skip_rows_block = block end
transactional(flag = true)
click to toggle source
Transactions
# File lib/active_importer/base.rb, line 89 def self.transactional(flag = true) if flag raise "Model class does not support transactions" unless @model_class.respond_to?(:transaction) end @transactional = !!flag end
transactional?()
click to toggle source
# File lib/active_importer/base.rb, line 96 def self.transactional? @transactional || false end
Private Class Methods
fetch_model_block()
click to toggle source
# File lib/active_importer/base.rb, line 44 def self.fetch_model_block @fetch_model_block end
fire_event(instance, event, param = nil)
click to toggle source
# File lib/active_importer/base.rb, line 146 def self.fire_event(instance, event, param = nil) event_handlers[event].each do |block| instance.instance_exec(param, &block) end end
skip_row_blocks()
click to toggle source
# File lib/active_importer/base.rb, line 246 def self.skip_row_blocks @skip_row_blocks ||= begin klass = self result = [] while klass < ActiveImporter::Base block = klass.skip_rows_block result << block if block klass = klass.superclass end result end end
Public Instance Methods
abort!(message)
click to toggle source
# File lib/active_importer/base.rb, line 12 def abort!(message) @abort_message = message end
aborted?()
click to toggle source
# File lib/active_importer/base.rb, line 16 def aborted? !!@abort_message end
fetch_model()
click to toggle source
# File lib/active_importer/base.rb, line 193 def fetch_model if fetch_model_block self.instance_exec(&fetch_model_block) else model_class.new end end
fetch_model_block()
click to toggle source
# File lib/active_importer/base.rb, line 189 def fetch_model_block self.class.send(:fetch_model_block) end
import()
click to toggle source
# File lib/active_importer/base.rb, line 201 def import transaction do return if @book.nil? fire_event :import_started @data_row_indices.each do |index| @row_index = index @row = row_to_hash @book.row(index) if skip_row? fire_event :row_skipped next end import_row if aborted? fire_event :import_aborted, @abort_message break end end end rescue => e fire_event :import_aborted, e.message raise ensure fire_event :import_finished end
model_class()
click to toggle source
# File lib/active_importer/base.rb, line 32 def model_class self.class.model_class end
row_error_count()
click to toggle source
# File lib/active_importer/base.rb, line 236 def row_error_count row_errors.count end
row_processed_count()
click to toggle source
# File lib/active_importer/base.rb, line 226 def row_processed_count row_index - @header_index rescue 0 end
row_success_count()
click to toggle source
# File lib/active_importer/base.rb, line 232 def row_success_count row_processed_count - row_errors.count end
transactional?()
click to toggle source
# File lib/active_importer/base.rb, line 100 def transactional? @transactional || self.class.transactional? end
Private Instance Methods
build_model()
click to toggle source
# File lib/active_importer/base.rb, line 310 def build_model row.each_pair do |key, value| column_def = columns[key] next if column_def.nil? || column_def[:field_name].nil? field_name = column_def[:field_name] transform = column_def[:transform] value = self.instance_exec(value, &transform) if transform model.send("#{field_name}=", value) end fire_event :row_processing end
columns()
click to toggle source
# File lib/active_importer/base.rb, line 242 def columns self.class.columns end
find_header_index()
click to toggle source
# File lib/active_importer/base.rb, line 271 def find_header_index required_column_keys = columns.keys.reject { |title| columns[title][:optional] } (1..@book.last_row).each do |index| row = @book.row(index).map { |cell| cell.to_s.strip } return index if required_column_keys.all? { |item| row.include?(item) } end return nil end
fire_event(event, param = nil)
click to toggle source
# File lib/active_importer/base.rb, line 139 def fire_event(event, param = nil) self.class.send(:fire_event, self, event, param) unless self.class == ActiveImporter::Base self.class.superclass.send(:fire_event, self, event, param) end end
import_row()
click to toggle source
# File lib/active_importer/base.rb, line 289 def import_row begin @model = fetch_model build_model save_model unless aborted? rescue => e @row_errors << { row_index: row_index, error_message: e.message } fire_event :row_error, e raise if transactional? return false end fire_event :row_success true ensure fire_event :row_processed end
load_header()
click to toggle source
# File lib/active_importer/base.rb, line 280 def load_header @header_index = find_header_index if @header_index @header = @book.row(@header_index).map(&:to_s).map(&:strip) else raise 'Spreadsheet does not contain all the expected columns' end end
load_sheet()
click to toggle source
# File lib/active_importer/base.rb, line 263 def load_sheet sheet_index = self.class.instance_variable_get(:@sheet_index) if sheet_index sheet_index = @book.sheets[sheet_index-1] if sheet_index.is_a?(Fixnum) @book.default_sheet = sheet_index.to_s end end
row_to_hash(row)
click to toggle source
# File lib/active_importer/base.rb, line 322 def row_to_hash(row) hash = {} row.each_with_index do |value, index| hash[@header[index]] = value end hash end
save_model()
click to toggle source
# File lib/active_importer/base.rb, line 306 def save_model model.save! if model.new_record? || model.changed? end
skip_row?()
click to toggle source
# File lib/active_importer/base.rb, line 259 def skip_row? self.class.skip_row_blocks.any? { |block| self.instance_exec(&block) } end
transaction() { || ... }
click to toggle source
# File lib/active_importer/base.rb, line 104 def transaction if transactional? model_class.transaction { yield } else yield end end