22module ActiveAdminImport
33 class Importer
44
5- attr_reader :resource , :options , :result , :headers , :csv_lines , :model
5+
6+ attr_reader :resource , :options , :result , :headers , :csv_lines , :model
7+
8+
9+ OPTIONS = [
10+ :validate ,
11+ :on_duplicate_key_update ,
12+ :ignore ,
13+ :timestamps ,
14+ :before_import ,
15+ :after_import ,
16+ :before_batch_import ,
17+ :after_batch_import ,
18+ :headers_rewrites ,
19+ :batch_size ,
20+ :csv_options
21+ ] . freeze
22+
623
724 def store
825 result = @resource . transaction do
9- options [ :before_batch_import ] . call ( self ) if options [ :before_batch_import ] . is_a? ( Proc )
10-
11- result = resource . import headers . values , csv_lines , {
12- validate : options [ :validate ] ,
13- on_duplicate_key_update : options [ :on_duplicate_key_update ] ,
14- ignore : options [ :ignore ] ,
15- timestamps : options [ :timestamps ]
16- }
17- options [ :after_batch_import ] . call ( self ) if options [ :after_batch_import ] . is_a? ( Proc )
26+ run_callback ( :before_batch_import )
27+ result = resource . import ( headers . values , csv_lines , options . slice ( :validate , :on_duplicate_key_update , :ignore , :timestamps ) )
28+ run_callback ( :after_batch_import )
1829 result
1930 end
2031 { imported : csv_lines . count - result . failed_instances . count , failed : result . failed_instances }
2132 end
2233
23- #
24- def prepare_headers ( headers )
25- @headers = Hash [ headers . zip ( headers . map { |el | el . underscore . gsub ( /\s +/ , '_' ) } ) ]
26- @headers . merge! ( options [ :headers_rewrites ] )
27- @headers
28- end
2934
3035 def initialize ( resource , model , options )
3136 @resource = resource
3237 @model = model
33- @options = { batch_size : 1000 , validate : true } . merge ( options )
3438 @headers = model . respond_to? ( :csv_headers ) ? model . csv_headers : [ ]
35- @result = { failed : [ ] , imported : 0 }
36- if @options . has_key? ( :col_sep ) || @options . has_key? ( :row_sep )
37- ActiveSupport ::Deprecation . warn "row_sep and col_sep options are deprecated, use csv_options to override default CSV options"
38- @csv_options = @options . slice ( :col_sep , :row_sep )
39- else
40- @csv_options = @options [ :csv_options ] || { }
41- end
42- #override csv options from model if it respond_to csv_options
43- @csv_options = model . csv_options if model . respond_to? ( :csv_options )
44- @csv_options . reject! { | key , value | value . blank? }
39+ assign_options ( options )
40+ end
4541
42+ def import_result
43+ @import_result ||= ImportResult . new
4644 end
4745
4846 def file
@@ -51,11 +49,11 @@ def file
5149
5250 def cycle ( lines )
5351 @csv_lines = CSV . parse ( lines . join , @csv_options )
54- @result . merge! ( self . store ) { | key , val1 , val2 | val1 + val2 }
52+ import_result . add ( batch_import , lines . count )
5553 end
5654
5755 def import
58- options [ :before_import ] . call ( self ) if options [ :before_import ] . is_a? ( Proc )
56+ run_callback ( :before_import )
5957 lines = [ ]
6058 batch_size = options [ :batch_size ] . to_i
6159 File . open ( file . path ) do |f |
@@ -65,14 +63,56 @@ def import
6563 next if line . blank?
6664 lines << line
6765 if lines . size == batch_size || f . eof?
68- cycle lines
66+ cycle ( lines )
6967 lines = [ ]
7068 end
7169 end
7270 end
7371 cycle ( lines ) unless lines . blank?
74- options [ :after_import ] . call ( self ) if options [ :after_import ] . is_a? ( Proc )
75- result
72+ run_callback ( :after_import )
73+ import_result
74+ end
75+
76+ def import_options
77+ @import_options ||= options . slice ( :validate , :on_duplicate_key_update , :ignore , :timestamps )
78+ end
79+
80+ protected
81+
82+ def prepare_headers ( headers )
83+ @headers = Hash [ headers . zip ( headers . map { |el | el . underscore . gsub ( /\s +/ , '_' ) } ) ]
84+ @headers . merge! ( options [ :headers_rewrites ] )
85+ @headers
86+ end
87+
88+ def run_callback ( name )
89+ options [ name ] . call ( self ) if options [ name ] . is_a? ( Proc )
90+ end
91+
92+ def batch_import
93+ @resource . transaction do
94+ run_callback ( :before_batch_import )
95+ batch_result = resource . import ( headers . values , csv_lines , import_options )
96+ run_callback ( :after_batch_import )
97+ batch_result
98+ end
99+ end
100+
101+
102+ private
103+
104+ def assign_options ( options )
105+ @options = { batch_size : 1000 , validate : true } . merge ( options . slice ( *OPTIONS ) )
106+ detect_csv_options
107+ end
108+
109+ def detect_csv_options
110+ @csv_options = if model . respond_to? ( :csv_options )
111+ model . csv_options
112+ else
113+ options [ :csv_options ] || { }
114+ end . reject { |_ , value | value . blank? }
76115 end
116+
77117 end
78118end
0 commit comments