rails-importer 0.0.7 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +64 -5
- data/config/locales/importers.en.yml +4 -1
- data/lib/generators/templates/generic_importer.erb +1 -0
- data/lib/rails_importer/base.rb +81 -41
- data/lib/rails_importer/version.rb +1 -1
- metadata +10 -12
- data/lib/rails_importer/_importer.rb +0 -138
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 21fedbfaf0623b35213ec6e37dafab5d3a11040ffaae8add9613e726743b441c
|
4
|
+
data.tar.gz: 3ba9d86e6cdd1b2cd4217c52b9718ebc2e654ac128d1d14551165891c3501282
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dddecdf677d03410d18c8df7977be529c5b571ee550263f40aff43544face6b4ef8a9227ae6c5e3f940db62640f49b6f0f6a098707bea9afeb3f7fbd1cb32f76
|
7
|
+
data.tar.gz: d20d9a502f0943fe733b655af1c42342565ed04461a3e5c2a4c9d4c86048786e41a16e849aea12c85c6f5a20135afd0efcd4489d320bb771b3e40f9c05d9c5f2
|
data/README.md
CHANGED
@@ -30,12 +30,17 @@ class ExampleImporter < RailsImporter::Base
|
|
30
30
|
|
31
31
|
importer do
|
32
32
|
fields :name, :email, :age
|
33
|
+
#or fields({:name => "Name", :email => "E-mail", :age => "Idade"})
|
33
34
|
each_record do |record, params|
|
35
|
+
|
34
36
|
MyModel.find_or_create_by(name: record[:name], email: record[:email], age: record[:age])
|
37
|
+
|
38
|
+
return record # or return wherever
|
35
39
|
end
|
36
40
|
end
|
37
41
|
|
38
42
|
# importer :simple do
|
43
|
+
# csv_params col_sep: ';'
|
39
44
|
# xml_structure :root, :row
|
40
45
|
# fields :name, :email, :age
|
41
46
|
# each_record do |record, params|
|
@@ -49,14 +54,68 @@ end
|
|
49
54
|
### How to use
|
50
55
|
|
51
56
|
You can call `import` from **Importers** objects:
|
52
|
-
|
57
|
+
**file param** must be an object that responds to `.path` method
|
58
|
+
```ruby
|
53
59
|
file = params[:import][:file]
|
54
|
-
records = ExampleImporter.import(file
|
60
|
+
records = ExampleImporter.import(file)
|
55
61
|
```
|
56
62
|
|
57
63
|
Or with context:
|
64
|
+
```ruby
|
65
|
+
file = params[:import][:file]
|
66
|
+
records = ExampleImporter.import(file, context: :simple)
|
67
|
+
```
|
68
|
+
|
69
|
+
Overwrite default fields (called in the block `importer do`):
|
70
|
+
```ruby
|
71
|
+
file = params[:import][:file]
|
72
|
+
records = ExampleImporter.import(file, fields: [:name, :email, :age])
|
73
|
+
```
|
58
74
|
|
59
|
-
|
75
|
+
With extra params:
|
76
|
+
```ruby
|
60
77
|
file = params[:import][:file]
|
61
|
-
records = ExampleImporter.import(file,
|
62
|
-
```
|
78
|
+
records = ExampleImporter.import(file, {user: 'john@mail.com'})
|
79
|
+
```
|
80
|
+
Then inside each record you can get params:
|
81
|
+
```ruby
|
82
|
+
class ExampleImporter < RailsImporter::Base
|
83
|
+
importer do
|
84
|
+
# ...
|
85
|
+
each_record do |record, params|
|
86
|
+
# ...
|
87
|
+
params[:user]
|
88
|
+
# ...
|
89
|
+
end
|
90
|
+
# ...
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
With full options:
|
96
|
+
```ruby
|
97
|
+
file = params[:import][:file]
|
98
|
+
records = ExampleImporter.import(file,
|
99
|
+
context: :simple,
|
100
|
+
fields: [:name, :email, :age],
|
101
|
+
{user: 'john@mail.com', account: '1'})
|
102
|
+
```
|
103
|
+
|
104
|
+
To return imported values, you need to return values inside of `each_record`:
|
105
|
+
```ruby
|
106
|
+
class ExampleImporter < RailsImporter::Base
|
107
|
+
importer do
|
108
|
+
# ...
|
109
|
+
each_record do |record, params|
|
110
|
+
# ...
|
111
|
+
u = Model.new(record)
|
112
|
+
u.created_by = params[:user]
|
113
|
+
ok = !!u.save
|
114
|
+
return {record: u, success: ok}
|
115
|
+
end
|
116
|
+
# ...
|
117
|
+
end
|
118
|
+
end
|
119
|
+
records = ExampleImporter.import(file, {user: 'john@mail.com'})
|
120
|
+
# [{record: ..., success: true}, {record: ..., success: false}]
|
121
|
+
```
|
data/lib/rails_importer/base.rb
CHANGED
@@ -8,18 +8,23 @@ module RailsImporter
|
|
8
8
|
class << self
|
9
9
|
def import(file, *args)
|
10
10
|
context = args.try(:context) || :default
|
11
|
+
custom_fields = args.try(:fields) || nil
|
11
12
|
result = []
|
12
13
|
begin
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
if file.respond_to?(:path)
|
15
|
+
ext = (File.extname(file.path)[1..-1] rescue '')
|
16
|
+
if self.file_types.include?(ext.to_sym)
|
17
|
+
rows = self.send('import_from_%s' % ext, file, context, custom_fields)
|
18
|
+
if rows.present? && rows.is_a?(Array)
|
19
|
+
result = rows.map do |record|
|
20
|
+
self.importers[context][:each_record].call(record, *args) if self.importers[context][:each_record].is_a?(Proc)
|
21
|
+
end.compact
|
22
|
+
end
|
23
|
+
else
|
24
|
+
result = I18n.t(:invalid_file_type, file_types: self.file_types.join(', '), scope: [:importer, :error])
|
20
25
|
end
|
21
26
|
else
|
22
|
-
I18n.t(:
|
27
|
+
result = I18n.t(:invalid_file, scope: [:importer, :error])
|
23
28
|
end
|
24
29
|
rescue Exception => e
|
25
30
|
result = e.message
|
@@ -37,8 +42,13 @@ module RailsImporter
|
|
37
42
|
# end
|
38
43
|
# end
|
39
44
|
|
40
|
-
def importer(name
|
41
|
-
(self.importers ||= {})[name] ||= {
|
45
|
+
def importer(name = :default, &block)
|
46
|
+
(self.importers ||= {})[name] ||= {
|
47
|
+
fields: [],
|
48
|
+
csv_params: {headers: false, col_sep: ',', force_quotes: true},
|
49
|
+
xml_structure: %i[records record],
|
50
|
+
each_record: nil
|
51
|
+
}
|
42
52
|
@importer_name = name
|
43
53
|
block.call if block_given?
|
44
54
|
self.importers[name]
|
@@ -52,24 +62,34 @@ module RailsImporter
|
|
52
62
|
importer_value(:xml_structure, attributes)
|
53
63
|
end
|
54
64
|
|
65
|
+
def csv_params(*attributes)
|
66
|
+
options = importer_value(:csv_params)
|
67
|
+
params = attributes.first
|
68
|
+
options = options.merge(params) if params.is_a?(Hash)
|
69
|
+
importer_value(:csv_params, options)
|
70
|
+
end
|
71
|
+
|
55
72
|
def each_record(&block)
|
56
73
|
importer_value(:each_record, block)
|
57
74
|
end
|
58
75
|
|
59
76
|
private
|
60
|
-
def import_from_csv(file, context
|
77
|
+
def import_from_csv(file, context = :default, custom_fields = :nil)
|
61
78
|
records = []
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
79
|
+
first_line = nil
|
80
|
+
options = self.importers[context][:csv_params]
|
81
|
+
CSV.foreach(file.path, options.merge(headers: false)) do |row|
|
82
|
+
# Skip headers
|
83
|
+
if first_line.nil?
|
84
|
+
first_line = row
|
85
|
+
next
|
66
86
|
end
|
67
|
-
|
87
|
+
records << object_values(row, context, custom_fields) unless array_blank?(row)
|
68
88
|
end
|
69
89
|
records
|
70
90
|
end
|
71
91
|
|
72
|
-
def import_from_xml(file, context
|
92
|
+
def import_from_xml(file, context = :default, custom_fields = :nil)
|
73
93
|
records = []
|
74
94
|
xml_structure = self.importers[context][:xml_structure]
|
75
95
|
xml = Hash.from_xml(file.read)
|
@@ -77,59 +97,79 @@ module RailsImporter
|
|
77
97
|
xml = xml[node.to_s]
|
78
98
|
end
|
79
99
|
xml.each do |elem|
|
80
|
-
records << object_values(elem.values, context) unless array_blank?(elem.values)
|
100
|
+
records << object_values(elem.values, context, custom_fields) unless array_blank?(elem.values)
|
81
101
|
end
|
82
102
|
records
|
83
103
|
end
|
84
104
|
|
85
|
-
def import_from_xls(file, context
|
105
|
+
def import_from_xls(file, context = :default, custom_fields = :nil)
|
86
106
|
records = []
|
87
107
|
Spreadsheet.client_encoding = 'UTF-8'
|
88
108
|
document = Spreadsheet.open(file.path)
|
89
109
|
spreadsheet = document.worksheet 0
|
90
110
|
spreadsheet.each_with_index do |row, i|
|
91
|
-
next
|
92
|
-
records << object_values(row, context) unless array_blank?(row)
|
111
|
+
next if i.zero?
|
112
|
+
records << object_values(row, context, custom_fields) unless array_blank?(row)
|
93
113
|
end
|
94
114
|
records
|
95
115
|
end
|
96
116
|
|
97
|
-
def object_values(array, context
|
98
|
-
attributes = self.importers[context][:fields]
|
117
|
+
def object_values(array, context = :default, custom_fields = nil)
|
118
|
+
attributes = custom_fields || self.importers[context][:fields]
|
99
119
|
attributes = attributes.keys if attributes.is_a?(Hash)
|
100
|
-
|
101
|
-
|
120
|
+
values = equalize_columns_of_values(attributes, array)
|
121
|
+
hash_values = Hash[attributes.zip(values)]
|
102
122
|
attributes.each do |attr|
|
103
|
-
if
|
104
|
-
if
|
105
|
-
|
106
|
-
|
107
|
-
elsif
|
108
|
-
|
109
|
-
elsif
|
110
|
-
|
123
|
+
if hash_values[attr].present?
|
124
|
+
if hash_values[attr].is_a?(Numeric)
|
125
|
+
hash_values[attr] = hash_values[attr].to_i if hash_values[attr].modulo(1).zero?
|
126
|
+
hash_values[attr] = (hash_values[attr].to_s.strip rescue I18n.t(:convert_number_to_text, scope: [:importer, :error]))
|
127
|
+
elsif hash_values[attr].is_a?(Date)
|
128
|
+
hash_values[attr] = (I18n.l(hash_values[attr], format: '%d/%m/%Y') rescue hash_values[attr]).to_s
|
129
|
+
elsif hash_values[attr].is_a?(DateTime)
|
130
|
+
hash_values[attr] = (I18n.l(hash_values[attr], format: '%d/%m/%Y %H:%i:%s') rescue hash_values[attr]).to_s
|
111
131
|
else
|
112
132
|
#PARA QUALQUER OUTRO VALOR, FORÇA CONVERTER PARA STRING
|
113
|
-
|
133
|
+
hash_values[attr] = (hash_values[attr].to_s.strip rescue '')
|
114
134
|
end
|
115
135
|
else
|
116
|
-
|
136
|
+
hash_values[attr] = ''
|
117
137
|
end
|
118
138
|
end
|
119
|
-
OpenStruct.new(
|
139
|
+
OpenStruct.new(hash_values)
|
120
140
|
end
|
121
141
|
|
122
142
|
def array_blank?(array)
|
123
|
-
array.all?
|
143
|
+
array.all?(&:blank?)
|
144
|
+
end
|
145
|
+
|
146
|
+
def importer_value(key, attributes=nil)
|
147
|
+
return self.importers[@importer_name][key] if attributes.nil?
|
148
|
+
attributes = normalize_fields(attributes) if key == :fields
|
149
|
+
self.importers[@importer_name][key] = attributes
|
124
150
|
end
|
125
151
|
|
126
|
-
def
|
127
|
-
if attributes.
|
128
|
-
|
152
|
+
def normalize_fields(attributes)
|
153
|
+
if attributes.first.is_a?(Hash)
|
154
|
+
attributes.inject(:merge)
|
155
|
+
elsif attributes.first.is_a?(Array)
|
156
|
+
attributes.flatten
|
129
157
|
else
|
130
|
-
|
158
|
+
attributes
|
131
159
|
end
|
132
160
|
end
|
161
|
+
|
162
|
+
def equalize_columns_of_values(attributes, values=[])
|
163
|
+
if attributes.size > values.size
|
164
|
+
diff_size = (attributes.size - values.size).abs
|
165
|
+
values + Array.new(diff_size, nil)
|
166
|
+
elsif attributes.size < values.size
|
167
|
+
values[0...attributes.size]
|
168
|
+
else
|
169
|
+
values
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
133
173
|
end
|
134
174
|
|
135
175
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-importer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno Porto
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,20 +16,20 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '4'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '7'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '4'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: spreadsheet
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,7 +67,6 @@ files:
|
|
67
67
|
- lib/generators/templates/generic_importer.erb
|
68
68
|
- lib/rails-importer.rb
|
69
69
|
- lib/rails_importer.rb
|
70
|
-
- lib/rails_importer/_importer.rb
|
71
70
|
- lib/rails_importer/base.rb
|
72
71
|
- lib/rails_importer/engine.rb
|
73
72
|
- lib/rails_importer/version.rb
|
@@ -75,7 +74,7 @@ homepage: https://github.com/brunoporto/rails-importer
|
|
75
74
|
licenses:
|
76
75
|
- MIT
|
77
76
|
metadata: {}
|
78
|
-
post_install_message:
|
77
|
+
post_install_message:
|
79
78
|
rdoc_options: []
|
80
79
|
require_paths:
|
81
80
|
- lib
|
@@ -90,9 +89,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
89
|
- !ruby/object:Gem::Version
|
91
90
|
version: '0'
|
92
91
|
requirements: []
|
93
|
-
|
94
|
-
|
95
|
-
signing_key:
|
92
|
+
rubygems_version: 3.2.15
|
93
|
+
signing_key:
|
96
94
|
specification_version: 4
|
97
95
|
summary: Rails Importer
|
98
96
|
test_files: []
|
@@ -1,138 +0,0 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
|
3
|
-
module RailsImporter
|
4
|
-
|
5
|
-
def self.included(base)
|
6
|
-
base.extend ClassMethods
|
7
|
-
|
8
|
-
base.define_singleton_method 'colunas' do |*args|
|
9
|
-
@importacao_colunas = nil unless @importacao_colunas.present?
|
10
|
-
if args.present?
|
11
|
-
@importacao_colunas = (args.first.is_a?(Hash) ? args.inject(:merge) : args)
|
12
|
-
else
|
13
|
-
@importacao_colunas
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
base.define_singleton_method 'estrutura_xml' do |*args|
|
18
|
-
@importacao_estrutura_xml = nil unless @importacao_estrutura_xml.present?
|
19
|
-
if args.present?
|
20
|
-
@importacao_estrutura_xml = args
|
21
|
-
else
|
22
|
-
@importacao_estrutura_xml
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
base.define_singleton_method 'para_cada_linha' do |&block|
|
27
|
-
define_singleton_method('importar_registro') do |registro, *args|
|
28
|
-
block.call(registro, *args)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.tipos_de_arquivos
|
35
|
-
[:csv, :xls, :xml]
|
36
|
-
end
|
37
|
-
|
38
|
-
module ClassMethods
|
39
|
-
|
40
|
-
def importacao(&block)
|
41
|
-
block.call if block_given?
|
42
|
-
self.class.class_eval do
|
43
|
-
define_method :importar do |arquivo, *args|
|
44
|
-
retorno = []
|
45
|
-
begin
|
46
|
-
ext = (File.extname(arquivo.path)[1..-1] rescue nil)
|
47
|
-
if arquivo.respond_to?(:path) and RailsImporter.tipos_de_arquivos.include?(ext.to_sym)
|
48
|
-
registros = self.send("#{ext}_para_array", arquivo)
|
49
|
-
if registros.present? and registros.is_a?(Array)
|
50
|
-
retorno = registros.map do |registro|
|
51
|
-
importar_registro(registro, *args)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
else
|
55
|
-
raise "Tipo de arquivo inválido. Arquivos permitidos: #{RailsImporter.tipos_de_arquivos.join(', ')}"
|
56
|
-
end
|
57
|
-
rescue Exception => e
|
58
|
-
retorno = e.message
|
59
|
-
end
|
60
|
-
retorno
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
def csv_para_array(arquivo)
|
67
|
-
registros = []
|
68
|
-
linha=0
|
69
|
-
CSV.foreach(arquivo.path, {:headers => false, :col_sep => ';', :force_quotes => true}) do |row|
|
70
|
-
if linha>0
|
71
|
-
registros << object_values(row) unless array_blank?(row)
|
72
|
-
end
|
73
|
-
linha+=1
|
74
|
-
end
|
75
|
-
registros
|
76
|
-
end
|
77
|
-
|
78
|
-
def xml_para_array(arquivo)
|
79
|
-
registros = []
|
80
|
-
estrutura_xml = self.send(:estrutura_xml)
|
81
|
-
if estrutura_xml.present? and estrutura_xml.is_a?(Array) and estrutura_xml.count > 0
|
82
|
-
xml = Hash.from_xml(arquivo.read)
|
83
|
-
estrutura_xml.each do |node|
|
84
|
-
xml = xml[node.to_s]
|
85
|
-
end
|
86
|
-
xml.each do |elem|
|
87
|
-
registros << object_values(elem.values) unless array_blank?(elem.values)
|
88
|
-
end
|
89
|
-
else
|
90
|
-
raise 'Você precisa informar a estrutura_xml no seu Model'
|
91
|
-
end
|
92
|
-
registros
|
93
|
-
end
|
94
|
-
|
95
|
-
def xls_para_array(arquivo)
|
96
|
-
registros = []
|
97
|
-
Spreadsheet.client_encoding = 'UTF-8'
|
98
|
-
documento = Spreadsheet.open(arquivo.path)
|
99
|
-
planilha = documento.worksheet 0
|
100
|
-
planilha.each_with_index do |row, i|
|
101
|
-
next unless i>0
|
102
|
-
registros << object_values(row) unless array_blank?(row)
|
103
|
-
end
|
104
|
-
registros
|
105
|
-
end
|
106
|
-
|
107
|
-
def object_values(array)
|
108
|
-
atributos = self.send(:colunas)
|
109
|
-
atributos = atributos.keys if atributos.is_a?(Hash)
|
110
|
-
args = array[0...atributos.size]
|
111
|
-
hValores = Hash[atributos.zip(args)]
|
112
|
-
#Ajustando valores inválidos
|
113
|
-
atributos.each do |atributo|
|
114
|
-
if hValores[atributo].present?
|
115
|
-
if hValores[atributo].is_a?(Numeric)
|
116
|
-
hValores[atributo] = hValores[atributo].to_i if hValores[atributo].modulo(1).zero?
|
117
|
-
hValores[atributo] = (hValores[atributo].to_s.strip rescue '#ERRO AO CONVERTER NUMERO PARA TEXTO')
|
118
|
-
elsif hValores[atributo].is_a?(Date)
|
119
|
-
hValores[atributo] = (I18n.l(hValores[atributo], format: '%d/%m/%Y') rescue hValores[atributo]).to_s
|
120
|
-
elsif hValores[atributo].is_a?(DateTime)
|
121
|
-
hValores[atributo] = (I18n.l(hValores[atributo], format: '%d/%m/%Y %H:%i:%s') rescue hValores[atributo]).to_s
|
122
|
-
else
|
123
|
-
#PARA QUALQUER OUTRO VALOR, FORÇA CONVERTER PARA STRING
|
124
|
-
hValores[atributo] = (hValores[atributo].to_s.strip rescue '')
|
125
|
-
end
|
126
|
-
else
|
127
|
-
hValores[atributo] = ''
|
128
|
-
end
|
129
|
-
end
|
130
|
-
OpenStruct.new(hValores)
|
131
|
-
end
|
132
|
-
|
133
|
-
def array_blank?(array)
|
134
|
-
array.all? {|i|i.nil? or i==''}
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
end
|