rails-importer 0.0.6 → 0.0.11
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 +63 -5
- data/config/locales/importers.en.yml +4 -1
- data/lib/rails_importer/base.rb +66 -35
- 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: 573081d673ea028ad52dedeb5b6492358a0e7e1e909b1f867e064bb01112ca9c
|
4
|
+
data.tar.gz: 83d313fdbd28f692b740e84c0ee2563f43f8ae2670489de0190da2db4e19bd5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a5f67741c4dd49bde921f88451fac6cc275b2270d7137380915c0c7fcb2ce2b93528b70b5029048a6dffa2b5ba6787b17a7258f8f6f8b22a4fc6cf28f1ac157
|
7
|
+
data.tar.gz: f6cf858f4b81136dd9af761a00a882548f42d25658143cc522811ecdc1439918c9f47ec0d41adc31a62d887b55538b0c77a9b225e3ac0145aa77dcfd73e1a3b8
|
data/README.md
CHANGED
@@ -30,8 +30,12 @@ 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
|
|
@@ -49,14 +53,68 @@ end
|
|
49
53
|
### How to use
|
50
54
|
|
51
55
|
You can call `import` from **Importers** objects:
|
52
|
-
|
56
|
+
**file param** must be an object that responds to `.path` method
|
57
|
+
```ruby
|
53
58
|
file = params[:import][:file]
|
54
|
-
records = ExampleImporter.import(file
|
59
|
+
records = ExampleImporter.import(file)
|
55
60
|
```
|
56
61
|
|
57
62
|
Or with context:
|
63
|
+
```ruby
|
64
|
+
file = params[:import][:file]
|
65
|
+
records = ExampleImporter.import(file, context: :simple)
|
66
|
+
```
|
67
|
+
|
68
|
+
Overwrite default fields (called in the block `importer do`):
|
69
|
+
```ruby
|
70
|
+
file = params[:import][:file]
|
71
|
+
records = ExampleImporter.import(file, fields: [:name, :email, :age])
|
72
|
+
```
|
58
73
|
|
59
|
-
|
74
|
+
With extra params:
|
75
|
+
```ruby
|
60
76
|
file = params[:import][:file]
|
61
|
-
records = ExampleImporter.import(file,
|
62
|
-
```
|
77
|
+
records = ExampleImporter.import(file, {user: 'john@mail.com'})
|
78
|
+
```
|
79
|
+
Then inside each record you can get params:
|
80
|
+
```ruby
|
81
|
+
class ExampleImporter < RailsImporter::Base
|
82
|
+
importer do
|
83
|
+
# ...
|
84
|
+
each_record do |record, params|
|
85
|
+
# ...
|
86
|
+
params[:user]
|
87
|
+
# ...
|
88
|
+
end
|
89
|
+
# ...
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
With full options:
|
95
|
+
```ruby
|
96
|
+
file = params[:import][:file]
|
97
|
+
records = ExampleImporter.import(file,
|
98
|
+
context: :simple,
|
99
|
+
fields: [:name, :email, :age],
|
100
|
+
{user: 'john@mail.com', account: '1'})
|
101
|
+
```
|
102
|
+
|
103
|
+
To return imported values, you need to return values inside of `each_record`:
|
104
|
+
```ruby
|
105
|
+
class ExampleImporter < RailsImporter::Base
|
106
|
+
importer do
|
107
|
+
# ...
|
108
|
+
each_record do |record, params|
|
109
|
+
# ...
|
110
|
+
u = Model.new(record)
|
111
|
+
u.created_by = params[:user]
|
112
|
+
ok = !!u.save
|
113
|
+
return {record: u, success: ok}
|
114
|
+
end
|
115
|
+
# ...
|
116
|
+
end
|
117
|
+
end
|
118
|
+
records = ExampleImporter.import(file, {user: 'john@mail.com'})
|
119
|
+
# [{record: ..., success: true}, {record: ..., success: false}]
|
120
|
+
```
|
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,7 +42,7 @@ module RailsImporter
|
|
37
42
|
# end
|
38
43
|
# end
|
39
44
|
|
40
|
-
def importer(name
|
45
|
+
def importer(name = :default, &block)
|
41
46
|
(self.importers ||= {})[name] ||= {fields: [], xml_structure: [:records, :record], each_record: nil}
|
42
47
|
@importer_name = name
|
43
48
|
block.call if block_given?
|
@@ -57,19 +62,19 @@ module RailsImporter
|
|
57
62
|
end
|
58
63
|
|
59
64
|
private
|
60
|
-
def import_from_csv(file, context
|
65
|
+
def import_from_csv(file, context = :default, custom_fields = :nil)
|
61
66
|
records = []
|
62
67
|
line = 0
|
63
68
|
CSV.foreach(file.path, {:headers => false, :col_sep => ';', :force_quotes => true}) do |row|
|
64
|
-
if line>0
|
65
|
-
records << object_values(row, context) unless array_blank?(row)
|
69
|
+
if line > 0
|
70
|
+
records << object_values(row, context, custom_fields) unless array_blank?(row)
|
66
71
|
end
|
67
|
-
line+=1
|
72
|
+
line += 1
|
68
73
|
end
|
69
74
|
records
|
70
75
|
end
|
71
76
|
|
72
|
-
def import_from_xml(file, context
|
77
|
+
def import_from_xml(file, context = :default, custom_fields = :nil)
|
73
78
|
records = []
|
74
79
|
xml_structure = self.importers[context][:xml_structure]
|
75
80
|
xml = Hash.from_xml(file.read)
|
@@ -77,59 +82,85 @@ module RailsImporter
|
|
77
82
|
xml = xml[node.to_s]
|
78
83
|
end
|
79
84
|
xml.each do |elem|
|
80
|
-
records << object_values(elem.values, context) unless array_blank?(elem.values)
|
85
|
+
records << object_values(elem.values, context, custom_fields) unless array_blank?(elem.values)
|
81
86
|
end
|
82
87
|
records
|
83
88
|
end
|
84
89
|
|
85
|
-
def import_from_xls(file, context
|
90
|
+
def import_from_xls(file, context = :default, custom_fields = :nil)
|
86
91
|
records = []
|
87
92
|
Spreadsheet.client_encoding = 'UTF-8'
|
88
93
|
document = Spreadsheet.open(file.path)
|
89
94
|
spreadsheet = document.worksheet 0
|
90
95
|
spreadsheet.each_with_index do |row, i|
|
91
|
-
next
|
92
|
-
records << object_values(row, context) unless array_blank?(row)
|
96
|
+
next if i.zero?
|
97
|
+
records << object_values(row, context, custom_fields) unless array_blank?(row)
|
93
98
|
end
|
94
99
|
records
|
95
100
|
end
|
96
101
|
|
97
|
-
def object_values(array, context
|
98
|
-
attributes = self.importers[context][:fields]
|
102
|
+
def object_values(array, context = :default, custom_fields = nil)
|
103
|
+
attributes = custom_fields || self.importers[context][:fields]
|
99
104
|
attributes = attributes.keys if attributes.is_a?(Hash)
|
100
|
-
|
101
|
-
|
105
|
+
values = equalize_columns_of_values(attributes, array)
|
106
|
+
hash_values = Hash[attributes.zip(values)]
|
102
107
|
attributes.each do |attr|
|
103
|
-
if
|
104
|
-
if
|
105
|
-
|
106
|
-
|
107
|
-
elsif
|
108
|
-
|
109
|
-
elsif
|
110
|
-
|
108
|
+
if hash_values[attr].present?
|
109
|
+
if hash_values[attr].is_a?(Numeric)
|
110
|
+
hash_values[attr] = hash_values[attr].to_i if hash_values[attr].modulo(1).zero?
|
111
|
+
hash_values[attr] = (hash_values[attr].to_s.strip rescue I18n.t(:convert_number_to_text, scope: [:importer, :error]))
|
112
|
+
elsif hash_values[attr].is_a?(Date)
|
113
|
+
hash_values[attr] = (I18n.l(hash_values[attr], format: '%d/%m/%Y') rescue hash_values[attr]).to_s
|
114
|
+
elsif hash_values[attr].is_a?(DateTime)
|
115
|
+
hash_values[attr] = (I18n.l(hash_values[attr], format: '%d/%m/%Y %H:%i:%s') rescue hash_values[attr]).to_s
|
111
116
|
else
|
112
117
|
#PARA QUALQUER OUTRO VALOR, FORÇA CONVERTER PARA STRING
|
113
|
-
|
118
|
+
hash_values[attr] = (hash_values[attr].to_s.strip rescue '')
|
114
119
|
end
|
115
120
|
else
|
116
|
-
|
121
|
+
hash_values[attr] = ''
|
117
122
|
end
|
118
123
|
end
|
119
|
-
OpenStruct.new(
|
124
|
+
OpenStruct.new(hash_values)
|
120
125
|
end
|
121
126
|
|
122
127
|
def array_blank?(array)
|
123
|
-
array.all?
|
128
|
+
array.all?(&:blank?)
|
124
129
|
end
|
125
130
|
|
126
131
|
def importer_value(key, attributes)
|
127
132
|
if attributes.present?
|
128
|
-
|
133
|
+
if key == :fields
|
134
|
+
self.importers[@importer_name][key] = normalize_fields(attributes)
|
135
|
+
else
|
136
|
+
self.importers[@importer_name][key] = attributes
|
137
|
+
end
|
129
138
|
else
|
130
139
|
self.importers[@importer_name][key]
|
131
140
|
end
|
132
141
|
end
|
142
|
+
|
143
|
+
def normalize_fields(attributes)
|
144
|
+
if attributes.first.is_a?(Hash)
|
145
|
+
attributes.inject(:merge)
|
146
|
+
elsif attributes.first.is_a?(Array)
|
147
|
+
attributes.flatten
|
148
|
+
else
|
149
|
+
attributes
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def equalize_columns_of_values(attributes, values=[])
|
154
|
+
if attributes.size > values.size
|
155
|
+
diff_size = (attributes.size - values.size).abs
|
156
|
+
values + Array.new(diff_size, nil)
|
157
|
+
elsif attributes.size < values.size
|
158
|
+
values[0...attributes.size]
|
159
|
+
else
|
160
|
+
values
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
133
164
|
end
|
134
165
|
|
135
166
|
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.11
|
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-18 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
|